From cfeb6527ec2346d8673b21af6f16000e80d079a8 Mon Sep 17 00:00:00 2001 From: starksama <257340800+starksama@users.noreply.github.com> Date: Fri, 13 Feb 2026 00:05:11 +0800 Subject: [PATCH 1/5] fix: recognize vault-only oracles as standard from scanner metadata When an oracle has only vault conversions (no feeds), the Morpho API returns null feeds, causing getOracleType to fallback to Custom. Now we trust the scanner metadata type for standard oracles too, not just meta oracles. This fixes markets like 0x72cc79... that use srRoyUSDC vault conversion. Fixes #381 --- src/utils/oracle.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/oracle.ts b/src/utils/oracle.ts index 619dd22c..bfcbd3ae 100644 --- a/src/utils/oracle.ts +++ b/src/utils/oracle.ts @@ -245,10 +245,11 @@ export function getOracleType( chainId?: number, metadataMap?: OracleMetadataRecord, ) { - // Check scanner metadata for meta oracle type + // Check scanner metadata for oracle type (meta or standard with vault-only) if (metadataMap && oracleAddress) { const metadata = getOracleFromMetadata(metadataMap, oracleAddress); if (metadata?.type === 'meta') return OracleType.Meta; + if (metadata?.type === 'standard') return OracleType.Standard; } // Morpho API only contains oracleData if it follows the standard MorphoOracle structure with feeds From 14f0f4ba1fe6d2bdf249ce9fa0b5a32edbd23a48 Mon Sep 17 00:00:00 2001 From: starksama <257340800+starksama@users.noreply.github.com> Date: Fri, 13 Feb 2026 00:15:05 +0800 Subject: [PATCH 2/5] fix: don't flag vault-only oracles as having unknown feeds When all feeds are null but scanner metadata shows a vault exists, treat it as a valid vault-only oracle instead of marking it as 'hasCompletelyUnknown'. This prevents false warnings on markets like srRoyUSDC that only use vault conversion. --- src/utils/oracle.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/utils/oracle.ts b/src/utils/oracle.ts index bfcbd3ae..b8a962c8 100644 --- a/src/utils/oracle.ts +++ b/src/utils/oracle.ts @@ -290,6 +290,24 @@ export function parsePriceFeedVendors( } if (!oracleData.baseFeedOne && !oracleData.baseFeedTwo && !oracleData.quoteFeedOne && !oracleData.quoteFeedTwo) { + // Check if this is a vault-only oracle (no feeds but has vault conversion) + const oracleMetadata = + options?.metadataMap && options.oracleAddress ? getOracleFromMetadata(options.metadataMap, options.oracleAddress) : undefined; + const oracleMetadataData = oracleMetadata?.data && !isMetaOracleData(oracleMetadata.data) ? oracleMetadata.data : undefined; + const hasVault = oracleMetadataData?.baseVault || oracleMetadataData?.quoteVault; + + // Vault-only oracles are valid — don't mark as unknown + if (hasVault) { + return { + coreVendors: [], + taggedVendors: [], + hasCompletelyUnknown: false, + hasTaggedUnknown: false, + vendors: [], + hasUnknown: false, + }; + } + return { coreVendors: [], taggedVendors: [], From 5f5768043211933c28b9812e18fd4394caaf6821 Mon Sep 17 00:00:00 2001 From: starksama <257340800+starksama@users.noreply.github.com> Date: Fri, 13 Feb 2026 00:20:40 +0800 Subject: [PATCH 3/5] fix: filter out false 'unrecognized asset' warnings using dynamic token list The subgraph fetcher only checks the static token list (supportedTokens), but we also have dynamic tokens from Pendle API via useTokensQuery. Now useMarketWarnings filters out 'unrecognized_loan_asset' and 'unrecognized_collateral_asset' warnings if the token IS found in the dynamic token list (which includes Pendle tokens). --- src/hooks/useMarketWarnings.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/hooks/useMarketWarnings.ts b/src/hooks/useMarketWarnings.ts index 5ba02b62..fd83267d 100644 --- a/src/hooks/useMarketWarnings.ts +++ b/src/hooks/useMarketWarnings.ts @@ -1,23 +1,41 @@ import { useMemo } from 'react'; import { useOracleMetadata, type OracleMetadataRecord } from '@/hooks/useOracleMetadata'; +import { useTokensQuery } from '@/hooks/queries/useTokensQuery'; import type { Market, WarningWithDetail } from '@/utils/types'; import { getMarketWarningsWithDetail } from '@/utils/warnings'; /** * Hook to compute market warnings with details on-demand * Uses oracle metadata when available for accurate feed detection + * Uses dynamic token list to filter out false "unrecognized asset" warnings */ export const useMarketWarnings = (market: Market | null | undefined): WarningWithDetail[] => { const chainId = market?.morphoBlue?.chain?.id; const { data: oracleMetadataMap } = useOracleMetadata(chainId); + const { findToken } = useTokensQuery(); return useMemo(() => { if (!market) return []; - return getMarketWarningsWithDetail(market, { + + const warnings = getMarketWarningsWithDetail(market, { considerWhitelist: true, oracleMetadataMap, }); - }, [market, oracleMetadataMap]); + + // Filter out false "unrecognized asset" warnings + // The subgraph fetcher only checks static token list, but we have dynamic tokens too (Pendle, etc.) + return warnings.filter((warning) => { + if (warning.code === 'unrecognized_loan_asset' && market.loanAsset?.address) { + const found = findToken(market.loanAsset.address, chainId ?? 0); + if (found) return false; // Token found in dynamic list, remove warning + } + if (warning.code === 'unrecognized_collateral_asset' && market.collateralAsset?.address) { + const found = findToken(market.collateralAsset.address, chainId ?? 0); + if (found) return false; // Token found in dynamic list, remove warning + } + return true; + }); + }, [market, oracleMetadataMap, findToken, chainId]); }; /** From 8e4d5b118ee068ea2de2c0e506210627ec3d2d90 Mon Sep 17 00:00:00 2001 From: starksama <257340800+starksama@users.noreply.github.com> Date: Fri, 13 Feb 2026 00:27:39 +0800 Subject: [PATCH 4/5] fix: show checkmark icon and proper tooltip for vault-only oracles For oracles that only use vault conversion (no price feeds): - Show green checkmark icon instead of empty badge - Tooltip explains: 'Uses onchain vault contract for price conversion' Previously showed nothing with confusing 'Uses feeds from .' tooltip. --- .../components/oracle-vendor-badge.tsx | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/features/markets/components/oracle-vendor-badge.tsx b/src/features/markets/components/oracle-vendor-badge.tsx index 2a98e833..ab2bfca8 100644 --- a/src/features/markets/components/oracle-vendor-badge.tsx +++ b/src/features/markets/components/oracle-vendor-badge.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Tooltip } from '@/components/ui/tooltip'; import Image from 'next/image'; -import { IoWarningOutline, IoHelpCircleOutline } from 'react-icons/io5'; +import { IoWarningOutline, IoHelpCircleOutline, IoCheckmarkCircleOutline } from 'react-icons/io5'; import { OracleType, OracleVendorIcons, @@ -50,6 +50,17 @@ function OracleVendorBadge({ oracleData, chainId, oracleAddress, showText = fals const isCustom = oracleType === OracleType.Custom; const isMeta = oracleType === OracleType.Meta; + // Check if this is a vault-only oracle (no feeds, only vault conversion) + const oracleMetadata = oracleMetadataMap && oracleAddress ? getOracleFromMetadata(oracleMetadataMap, oracleAddress) : undefined; + const oracleMetadataData = oracleMetadata?.data && !isMetaOracleData(oracleMetadata.data) ? oracleMetadata.data : undefined; + const isVaultOnly = + oracleType === OracleType.Standard && + !oracleMetadataData?.baseFeedOne && + !oracleMetadataData?.baseFeedTwo && + !oracleMetadataData?.quoteFeedOne && + !oracleMetadataData?.quoteFeedTwo && + (oracleMetadataData?.baseVault || oracleMetadataData?.quoteVault); + const vendorInfo = (() => { if (isMeta && oracleMetadataMap && oracleAddress) { const metadata = getOracleFromMetadata(oracleMetadataMap, oracleAddress); @@ -72,6 +83,12 @@ function OracleVendorBadge({ oracleData, chainId, oracleAddress, showText = fals className="text-secondary" size={16} /> + ) : isVaultOnly ? ( + // Vault-only oracle - show checkmark icon + ) : hasCompletelyUnknown || hasTaggedUnknown ? ( // Show core vendor icons plus question mark for any unknown types <> @@ -101,6 +118,16 @@ function OracleVendorBadge({ oracleData, chainId, oracleAddress, showText = fals ); } + // Vault-only oracle - special case + if (isVaultOnly) { + return ( +
+

Standard Oracle

+

Uses onchain vault contract for price conversion.

+
+ ); + } + const oracleLabel = isMeta ? 'Meta Oracle' : 'Standard Oracle'; if (hasCompletelyUnknown || hasTaggedUnknown) { From ff8c0a0266cf27d64bb71c5a83f618667860fb1c Mon Sep 17 00:00:00 2001 From: antoncoding Date: Fri, 13 Feb 2026 00:31:38 +0800 Subject: [PATCH 5/5] chore: remove unnecessary hardcodes --- src/features/markets/components/oracle-vendor-badge.tsx | 2 +- src/utils/markets.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/features/markets/components/oracle-vendor-badge.tsx b/src/features/markets/components/oracle-vendor-badge.tsx index ab2bfca8..c1127fee 100644 --- a/src/features/markets/components/oracle-vendor-badge.tsx +++ b/src/features/markets/components/oracle-vendor-badge.tsx @@ -86,7 +86,7 @@ function OracleVendorBadge({ oracleData, chainId, oracleAddress, showText = fals ) : isVaultOnly ? ( // Vault-only oracle - show checkmark icon ) : hasCompletelyUnknown || hasTaggedUnknown ? ( diff --git a/src/utils/markets.ts b/src/utils/markets.ts index 9a030dce..6fed0c14 100644 --- a/src/utils/markets.ts +++ b/src/utils/markets.ts @@ -40,10 +40,6 @@ export const monarchWhitelistedMarkets: WhitelistMarketData[] = [ id: '0x74918a8744b4a48d233e66d0f6a318ef847cc4da2910357897f94a33c3481280', // sPinto/USDC by Pinto offsetWarnings: ['unrecognized_collateral_asset'], }, - { - id: '0x9bc98c2f20ac58287ef2c860eea53a2fdc27c17a7817ff1206c0b7840cc7cd79', // Morpho API stopped tracking PT markets - offsetWarnings: ['unrecognized_collateral_asset'], - }, ]; // Market override rules - group multiple markets under the same rule