Skip to content
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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

TalDerei
Copy link
Contributor

references #188

@TalDerei TalDerei self-assigned this Dec 18, 2024
@TalDerei TalDerei marked this pull request as draft December 18, 2024 05:21
queries: quoteAssets.map(asset => ({
queryKey: ['multipleSummaries', asset, 'USDC'] as const,
queryFn: async () => {
return apiFetch<SummaryData | NoSummaryData>('/api/summary', {
Copy link
Contributor Author

@TalDerei TalDerei Dec 18, 2024

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
Copy link
Contributor Author

@TalDerei TalDerei Dec 18, 2024

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?

Copy link
Contributor

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 = (
Copy link
Contributor Author

@TalDerei TalDerei Dec 18, 2024

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

Copy link
Contributor

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.

Copy link
Contributor

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);
Copy link
Contributor Author

@TalDerei TalDerei Dec 18, 2024

Choose a reason for hiding this comment

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

why do pairs displayed on the explore page occasionally flip? Compare SHITMOS / UM versus UM / SHITMOS for instance


'Screenshot 2024-12-17 at 12 28 19 PM

Screenshot 2024-12-17 at 8 40 06 PM

@@ -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;
Copy link
Contributor Author

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();

@TalDerei TalDerei marked this pull request as ready for review December 18, 2024 06:58
Copy link
Contributor

@VanishMax VanishMax left a 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]!;
Copy link
Contributor Author

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'}
Copy link
Contributor

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'}
Copy link
Contributor

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;
Copy link
Contributor

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
Copy link
Contributor

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 = (
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants