-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
explore page: use common numeraire #223
base: main
Are you sure you want to change the base?
Conversation
queries: quoteAssets.map(asset => ({ | ||
queryKey: ['multipleSummaries', asset, 'USDC'] as const, | ||
queryFn: async () => { | ||
return apiFetch<SummaryData | NoSummaryData>('/api/summary', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that the /api/stats
and /api/summaries
endpoints from pindexer may be returning incorrect information, impacting metrics like "total trading volume (24h)" and the largest "trading pair (24h volume)" for the USDC/USDY pair.
previous discussions suggest that this may not simply be related to the denom exponents not being handled properly. cc @cronokirby
})), | ||
}); | ||
|
||
// TODO: add block-based fetching |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can't simply call useRefetchOnNewBlock('summary', queries)
since queries is a UseQueryResult[]
. suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: something like this would be forward compatible:
// Use this for your new hook
export const useMultipleRefetchOnNewBlock = (queryKey: string, queries: UseQueryResult[]) => {
const { data: blockHeight } = useLatestBlockHeight();
const queryKeyString = JSON.stringify(queryKey);
useEffect(() => {
if (!blockHeight) {
return;
}
const lastHeight = lastRefetchedBlockHeights.get(queryKeyString) ?? -1;
if (blockHeight > lastHeight) {
lastRefetchedBlockHeights.set(queryKeyString, blockHeight);
queries.forEach(query => {
void query.refetch();
});
}
}, [blockHeight, queries, queryKeyString]);
};
// The other ones can still use this
export const useRefetchOnNewBlock = (queryKey: string, query: UseQueryResult) => {
useMultipleRefetchOnNewBlock(queryKey, [query]);
};
/** | ||
* Calculates USDC-normalized amounts for trading pair values (volume or liquidity) | ||
*/ | ||
export const calculateScaledAmount = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shared price conversion utility; sanity check math
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: wonder if there is something in calculateDisplayPrice()
that relates to this. Feels like we should create a class or some type of math scaling utility that can handle all price/amount scaling between different denoms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, could be nice to extend the pnum
to allow add
, multiply
, subtract
methods
@@ -51,8 +54,49 @@ export const ExplorePairs = () => { | |||
|
|||
const [search, setSearch] = useState(''); | |||
|
|||
// Fetch trading pair summaries. | |||
const { data, isLoading, isRefetching, isFetchingNextPage, fetchNextPage } = useSummaries(search); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -5,7 +5,8 @@ import { SummaryData } from '@/shared/api/server/summary/types'; | |||
import { DurationWindow } from '@/shared/utils/duration'; | |||
import { apiFetch } from '@/shared/utils/api-fetch'; | |||
|
|||
const BASE_LIMIT = 15; | |||
/// The base limit will need to be increased as more trading pairs are added to the explore page. | |||
const BASE_LIMIT = 20; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
caps the number of pairs returned from calling useSummaries();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: is it possible to implement USDC price calculation using SQL?
As I understood the code correctly, it firstly calls useSummaries
, waits for it to fetch, and then makes multiple requests to /api/summary
with USDC as a quote asset. In my tests, these sequential requests run from 1s to 3s. It's not a bad score, but we can sure do better. Plus, I think that making multiple requests (right now 6 /api/summary
requests are made in parallel) are highly error prone and not-so-scalable.
We could change this to an improved SQL query. That's just one join with the sub-table where quote assets are USDC and multiplication method. This could also unblock sorting by calculated volume, limit and filter the results correctly.
issue (realized while writing question before): with this solution, we cannot sort the assets by usdc volume. For now, it is sorted by trade amount, which is not as useful for users as volume.
page.forEach((item, itemIndex) => { | ||
if (quoteAssetsList[itemIndex] !== 'USDC') { | ||
item.directVolume.valueView.value!.amount!.lo = volumePairs[itemIndex]!; | ||
item.liquidity.valueView.value!.amount!.lo = liquidityPairs[itemIndex]!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this assignment is what updates the volume and liquidity values to be displayed on the explore page.I think the page should complete the price conversion and asset loading before rendering. Otherwise, the page may load first, and the amounts will update afterward. That's not currently the case, and should be updated to reflect that accordingly.
Screen.Recording.2024-12-17.at.11.16.57.PM.mov
@@ -119,7 +119,7 @@ export const PairCard = ({ loading, summary }: PairCardProps) => { | |||
{shortify(Number(getFormattedAmtFromValueView(summary.liquidity)))} | |||
</Text> | |||
<Text detail color='text.secondary'> | |||
{summary.quoteAsset.symbol} | |||
{'USDC'} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: Let's pull the symbol from the valueview:
{getMetadata(summary.liquidity).symbol}
@@ -134,7 +134,7 @@ export const PairCard = ({ loading, summary }: PairCardProps) => { | |||
{shortify(Number(getFormattedAmtFromValueView(summary.directVolume)))} | |||
</Text> | |||
<Text detail color='text.secondary'> | |||
{summary.quoteAsset.symbol} | |||
{'USDC'} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: same as above
{getMetadata(summary.directValue).symbol}
const { data, isLoading, isRefetching, isFetchingNextPage, fetchNextPage } = useSummaries(search); | ||
|
||
// Create temporary translator to normalize volumes/liquidity to USDC values. | ||
// Deep clone is neccesary since objects are passed by reference in typeScript. | ||
let translator = data?.pages ? structuredClone(data.pages) : undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I think we should consider moving all of this logic to the backend and have it just return the Value
type (already denominated in USDC). And then the web app is only responsible for promoting the Value to a ValueView with the registry. Some patterns here to consider.
})), | ||
}); | ||
|
||
// TODO: add block-based fetching |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: something like this would be forward compatible:
// Use this for your new hook
export const useMultipleRefetchOnNewBlock = (queryKey: string, queries: UseQueryResult[]) => {
const { data: blockHeight } = useLatestBlockHeight();
const queryKeyString = JSON.stringify(queryKey);
useEffect(() => {
if (!blockHeight) {
return;
}
const lastHeight = lastRefetchedBlockHeights.get(queryKeyString) ?? -1;
if (blockHeight > lastHeight) {
lastRefetchedBlockHeights.set(queryKeyString, blockHeight);
queries.forEach(query => {
void query.refetch();
});
}
}, [blockHeight, queries, queryKeyString]);
};
// The other ones can still use this
export const useRefetchOnNewBlock = (queryKey: string, query: UseQueryResult) => {
useMultipleRefetchOnNewBlock(queryKey, [query]);
};
/** | ||
* Calculates USDC-normalized amounts for trading pair values (volume or liquidity) | ||
*/ | ||
export const calculateScaledAmount = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: wonder if there is something in calculateDisplayPrice()
that relates to this. Feels like we should create a class or some type of math scaling utility that can handle all price/amount scaling between different denoms.
references #188