diff --git a/src/features/markets/components/oracle-vendor-badge.tsx b/src/features/markets/components/oracle-vendor-badge.tsx
index 2a98e833..c1127fee 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) {
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]);
};
/**
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
diff --git a/src/utils/oracle.ts b/src/utils/oracle.ts
index 619dd22c..b8a962c8 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
@@ -289,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: [],