diff --git a/src/shared/api/server/summary/all.ts b/src/shared/api/server/summary/all.ts index c4b55eaa..59d9eaf5 100644 --- a/src/shared/api/server/summary/all.ts +++ b/src/shared/api/server/summary/all.ts @@ -5,6 +5,8 @@ import { DurationWindow, durationWindows, isDurationWindow } from '@/shared/util import { adaptSummary, SummaryData } from '@/shared/api/server/summary/types.ts'; import { AssetId, Metadata } from '@penumbra-zone/protobuf/penumbra/core/asset/v1/asset_pb'; import { serialize, Serialized } from '@/shared/utils/serializer'; +import { getStablecoins } from '@/shared/utils/stables'; +import { getFormattedAmtFromValueView } from '@penumbra-zone/types/value-view'; interface GetPairsParams { window: DurationWindow; @@ -31,8 +33,7 @@ export const getAllSummaries = async ( const registry = await registryClient.remote.get(chainId); const allAssets = registry.getAllAssets(); - const stablecoins = allAssets.filter(asset => ['USDT', 'USDC', 'USDY'].includes(asset.symbol)); - const usdc = stablecoins.find(asset => asset.symbol === 'USDC'); + const { stablecoins, usdc } = getStablecoins(allAssets, 'USDC'); const results = await pindexer.summaries({ ...params, @@ -66,11 +67,24 @@ export const getAllSummaries = async ( return; } - return serialize(data); + return data; }), ); - return summaries.filter(Boolean) as Serialized[]; + // Sorting by decreasing liquidity in the pool + // TODO: sort directly in SQL to avoid breaking server-side pagination + const sortedSummaries = summaries.filter(Boolean).sort((a, b) => { + if (!a || !b) { + return 0; + } + + const aLiquidity = Number(getFormattedAmtFromValueView(a.liquidity)) || 0; + const bLiquidity = Number(getFormattedAmtFromValueView(b.liquidity)) || 0; + + return bLiquidity - aLiquidity; + }); + + return sortedSummaries.map(data => serialize(data)) as Serialized[]; }; export type SummariesResponse = Serialized[] | { error: string }; diff --git a/src/shared/api/server/summary/pairs.ts b/src/shared/api/server/summary/pairs.ts index 02914370..c44e7099 100644 --- a/src/shared/api/server/summary/pairs.ts +++ b/src/shared/api/server/summary/pairs.ts @@ -8,7 +8,8 @@ import { } from '@penumbra-zone/protobuf/penumbra/core/asset/v1/asset_pb'; import { ChainRegistryClient } from '@penumbra-labs/registry'; import { toValueView } from '@/shared/utils/value-view'; -import { getDisplayDenomExponent } from '@penumbra-zone/getters/metadata'; +import { getStablecoins } from '@/shared/utils/stables'; +import { calculateEquivalentInUSDC } from '@/shared/utils/price-conversion'; const getAssetById = (allAssets: Metadata[], id: Buffer): Metadata | undefined => { return allAssets.find(asset => { @@ -34,8 +35,7 @@ export async function GET(): Promise> { const registry = await registryClient.remote.get(chainId); const allAssets = registry.getAllAssets(); - const stablecoins = allAssets.filter(asset => ['USDT', 'USDC', 'USDY'].includes(asset.symbol)); - const usdc = stablecoins.find(asset => asset.symbol === 'USDC'); + const { stablecoins, usdc } = getStablecoins(allAssets, 'USDC'); const results = await pindexer.pairs({ // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style -- usdc is defined @@ -58,15 +58,8 @@ export async function GET(): Promise> { }); // Converts liquidity and trading volume to their equivalent USDC prices if `usdc_price` is available - if (summary.usdc_price) { - const expDiff = Math.abs( - getDisplayDenomExponent(quoteAsset) - getDisplayDenomExponent(usdc), - ); - const result = summary.liquidity * summary.usdc_price * 10 ** expDiff; - volume = toValueView({ - amount: Math.floor(result), - metadata: quoteAsset, - }); + if (summary.usdc_price && usdc) { + volume = calculateEquivalentInUSDC(summary.liquidity, summary.usdc_price, quoteAsset, usdc); } return serialize({ diff --git a/src/shared/api/server/summary/single.ts b/src/shared/api/server/summary/single.ts index 573892bb..c4348d15 100644 --- a/src/shared/api/server/summary/single.ts +++ b/src/shared/api/server/summary/single.ts @@ -4,6 +4,7 @@ import { ChainRegistryClient } from '@penumbra-labs/registry'; import { durationWindows, isDurationWindow } from '@/shared/utils/duration.ts'; import { adaptSummary, SummaryResponse } from '@/shared/api/server/summary/types.ts'; import { serialize, Serialized } from '@/shared/utils/serializer'; +import { getStablecoins } from '@/shared/utils/stables'; export async function GET(req: NextRequest): Promise>> { const chainId = process.env['PENUMBRA_CHAIN_ID']; @@ -34,8 +35,8 @@ export async function GET(req: NextRequest): Promise ['USDT', 'USDC', 'USDY'].includes(asset.symbol)); - const usdc = stablecoins.find(asset => asset.symbol === 'USDC'); + + const { usdc } = getStablecoins(allAssets, 'USDC'); const baseAssetMetadata = allAssets.find( a => a.symbol.toLowerCase() === baseAssetSymbol.toLowerCase(), diff --git a/src/shared/utils/stables.ts b/src/shared/utils/stables.ts new file mode 100644 index 00000000..5a391d20 --- /dev/null +++ b/src/shared/utils/stables.ts @@ -0,0 +1,13 @@ +import { Metadata } from '@penumbra-zone/protobuf/penumbra/core/asset/v1/asset_pb'; + +/** + * Utility for retrieving stablecoin metadata + */ +export const getStablecoins = ( + allAssets: Metadata[], + stablecoin: string, +): { stablecoins: Metadata[]; usdc?: Metadata } => { + const stablecoins = allAssets.filter(asset => ['USDT', 'USDC', 'USDY'].includes(asset.symbol)); + const usdc = stablecoins.find(asset => asset.symbol === stablecoin); + return { stablecoins, usdc }; +};