From f7eb3863979660e98e48ae98112fd10823788728 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Mon, 13 Oct 2025 12:30:44 +0800 Subject: [PATCH 1/3] feat: badDebt warning --- src/data-sources/subgraph/market.ts | 11 +++--- src/graphql/morpho-api-queries.ts | 17 +++++++++ src/hooks/useMarketWarnings.ts | 5 +-- src/hooks/useUserPositionsSummaryData.ts | 2 +- src/store/createWagmiConfig.ts | 2 ++ src/utils/types.ts | 4 ++- src/utils/warnings.ts | 44 ++++++++---------------- 7 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/data-sources/subgraph/market.ts b/src/data-sources/subgraph/market.ts index 4c13e79b..87f794b8 100644 --- a/src/data-sources/subgraph/market.ts +++ b/src/data-sources/subgraph/market.ts @@ -108,12 +108,6 @@ const transformSubgraphMarketToMarket = ( const inputTokenPriceUSD = subgraphMarket.inputTokenPriceUSD ?? '0'; const oracleAddress = (subgraphMarket.oracle?.oracleAddress ?? '0x') as Address; - if ( - marketId.toLowerCase() === '0x9103c3b4e834476c9a62ea009ba2c884ee42e94e6e314a26f04d312434191836' - ) { - console.log('subgraphMarket', subgraphMarket); - } - const totalSupplyShares = subgraphMarket.totalSupplyShares ?? '0'; const totalBorrowShares = subgraphMarket.totalBorrowShares ?? '0'; const fee = subgraphMarket.fee ?? '0'; @@ -271,6 +265,11 @@ const transformSubgraphMarketToMarket = ( hasUSDPrice: hasUSDPrice, isProtectedByLiquidationBots: false, // Not available from subgraph isMonarchWhitelisted: false, + + // todo: not able to parse bad debt now + realizedBadDebt: { + underlying: '0' + } }; return marketDetail; diff --git a/src/graphql/morpho-api-queries.ts b/src/graphql/morpho-api-queries.ts index 1b6969f4..faa31252 100644 --- a/src/graphql/morpho-api-queries.ts +++ b/src/graphql/morpho-api-queries.ts @@ -67,6 +67,15 @@ warnings { __typename } +realizedBadDebt { + underlying + usd +} +badDebt { + underlying + usd +} + oracle { data { ... on MorphoChainlinkOracleData { @@ -171,6 +180,14 @@ export const marketsQuery = ` name decimals } + badDebt { + underlying + usd + } + realizedBadDebt { + underlying + usd + } state { borrowAssets supplyAssets diff --git a/src/hooks/useMarketWarnings.ts b/src/hooks/useMarketWarnings.ts index 1a100de9..28848836 100644 --- a/src/hooks/useMarketWarnings.ts +++ b/src/hooks/useMarketWarnings.ts @@ -7,7 +7,7 @@ import { getMarketWarningsWithDetail } from '@/utils/warnings'; * This separates data fetching concerns from presentation logic */ export const useMarketWarnings = ( - market: Pick, + market: Market, considerWhitelist = false, ): WarningWithDetail[] => { return useMemo(() => { @@ -18,6 +18,7 @@ export const useMarketWarnings = ( market.oracle, market.oracleAddress, market.morphoBlue?.chain?.id, + market.realizedBadDebt.underlying, considerWhitelist, ]); }; @@ -27,7 +28,7 @@ export const useMarketWarnings = ( * Use this in contexts where you can't use hooks */ export const computeMarketWarnings = ( - market: Pick, + market: Market, considerWhitelist = false, ): WarningWithDetail[] => { return getMarketWarningsWithDetail(market, considerWhitelist); diff --git a/src/hooks/useUserPositionsSummaryData.ts b/src/hooks/useUserPositionsSummaryData.ts index 8cf40071..3e4e6674 100644 --- a/src/hooks/useUserPositionsSummaryData.ts +++ b/src/hooks/useUserPositionsSummaryData.ts @@ -91,7 +91,7 @@ const useUserPositionsSummaryData = (user: string | undefined) => { queryKey: blockKeys.all, queryFn: fetchBlockNumbers, staleTime: 5 * 60 * 1000, // Consider block numbers fresh for 5 minutes - gcTime: 30 * 60 * 1000, // Keep in cache for 30 minutes + gcTime: 3 * 60 * 1000, // Keep in cache for 3 minutes }); // Query for earnings calculations with progressive updates diff --git a/src/store/createWagmiConfig.ts b/src/store/createWagmiConfig.ts index a71205ed..a6fcd7c7 100644 --- a/src/store/createWagmiConfig.ts +++ b/src/store/createWagmiConfig.ts @@ -8,6 +8,7 @@ import { injectedWallet, trustWallet, ledgerWallet, + walletConnectWallet } from '@rainbow-me/rainbowkit/wallets'; import { createConfig, http } from 'wagmi'; import { base, mainnet, polygon, unichain, arbitrum } from 'wagmi/chains'; @@ -26,6 +27,7 @@ const wallets = injectedWallet, trustWallet, ledgerWallet, + walletConnectWallet ] : [injectedWallet]; diff --git a/src/utils/types.ts b/src/utils/types.ts index a2a907a9..b7314237 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -292,7 +292,9 @@ export type Market = { timestamp: number; rateAtUTarget: number; }; - + realizedBadDebt: { + underlying: string + } // whether we have USD price such has supplyUSD, borrowUSD, collateralUSD, etc. If not, use estimationP hasUSDPrice: boolean; warnings: MarketWarning[]; diff --git a/src/utils/warnings.ts b/src/utils/warnings.ts index 17d84075..38a29650 100644 --- a/src/utils/warnings.ts +++ b/src/utils/warnings.ts @@ -1,4 +1,4 @@ -import { MarketWarning, MorphoChainlinkOracleData } from '@/utils/types'; +import { Market, MarketWarning } from '@/utils/types'; import { monarchWhitelistedMarkets } from './markets'; import { getOracleType, OracleType, parsePriceFeedVendors, checkFeedsPath } from './oracle'; import { WarningCategory, WarningWithDetail } from './types'; @@ -68,12 +68,7 @@ const morphoOfficialWarnings: WarningWithDetail[] = [ description: 'This market has some unrealized bad debt', category: WarningCategory.debt, }, - { - code: 'bad_debt_realized', - level: 'warning', - description: 'This market has some realized bad debt (>10 BPS of total supply)', - category: WarningCategory.debt, - }, + { code: 'not_whitelisted', level: 'alert', @@ -104,6 +99,13 @@ const subgraphWarnings: WarningWithDetail[] = [ }, ]; +const BAD_DEBT: WarningWithDetail = { + code: 'bad_debt_realized', + level: 'warning', + description: 'This market has some realized bad debt', + category: WarningCategory.debt, +} + const UNRECOGNIZED_ORACLE: WarningWithDetail = { code: 'unrecognized_oracle', level: 'alert', @@ -142,30 +144,9 @@ const UNRECOGNIZED_FEEDS_TAGGED: WarningWithDetail = { category: WarningCategory.oracle, }; -// { -// code: 'incorrect_loan_exchange_rate', -// level: 'warning', -// description: 'The market is using the exchange rate from a token different from the loan one. ', -// category: WarningCategory.oracle, -// }, -// { -// code: 'incorrect_collateral_exchange_rate', -// level: 'warning', -// description: -// 'The market is using the exchange rate from a token different from the collateral one.', -// category: WarningCategory.oracle, -// }, export const getMarketWarningsWithDetail = ( - market: { - warnings: MarketWarning[]; - uniqueKey: string; - oracle?: { data: MorphoChainlinkOracleData }; - oracleAddress?: string; - morphoBlue: { chain: { id: number } }; - loanAsset?: { symbol: string }; - collateralAsset?: { symbol: string }; - }, + market: Market, considerWhitelist = false, ) => { const result = []; @@ -200,6 +181,11 @@ export const getMarketWarningsWithDetail = ( } } + // append bad debt warnings // deprecated from Morpho API + if (BigInt(market.realizedBadDebt.underlying) > 0n) { + result.push(BAD_DEBT) + } + // append our own oracle warnings const oracleType = getOracleType( market.oracle?.data, From 8ef5b5e79ee90fdb5eaa2883d7fe7b802a97a7b0 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Mon, 13 Oct 2025 12:41:47 +0800 Subject: [PATCH 2/3] chore: not always append --- src/utils/warnings.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/utils/warnings.ts b/src/utils/warnings.ts index 38a29650..df6bb5bd 100644 --- a/src/utils/warnings.ts +++ b/src/utils/warnings.ts @@ -102,7 +102,7 @@ const subgraphWarnings: WarningWithDetail[] = [ const BAD_DEBT: WarningWithDetail = { code: 'bad_debt_realized', level: 'warning', - description: 'This market has some realized bad debt', + description: 'This market has some realized bad debt (>10 BPS of total supply)', category: WarningCategory.debt, } @@ -183,7 +183,11 @@ export const getMarketWarningsWithDetail = ( // append bad debt warnings // deprecated from Morpho API if (BigInt(market.realizedBadDebt.underlying) > 0n) { - result.push(BAD_DEBT) + + // only push the bad debt error is it's > 10BPS + if (BigInt(market.realizedBadDebt.underlying) * BigInt(1000) > BigInt(market.state.supplyAssets)) { + result.push(BAD_DEBT) + } } // append our own oracle warnings From 3d4674be1629f94f8b1b7da0b9b827e05789dc1d Mon Sep 17 00:00:00 2001 From: antoncoding Date: Mon, 13 Oct 2025 12:45:06 +0800 Subject: [PATCH 3/3] chore: type safe --- src/utils/warnings.ts | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/utils/warnings.ts b/src/utils/warnings.ts index df6bb5bd..a617fb09 100644 --- a/src/utils/warnings.ts +++ b/src/utils/warnings.ts @@ -181,16 +181,24 @@ export const getMarketWarningsWithDetail = ( } } - // append bad debt warnings // deprecated from Morpho API - if (BigInt(market.realizedBadDebt.underlying) > 0n) { - - // only push the bad debt error is it's > 10BPS - if (BigInt(market.realizedBadDebt.underlying) * BigInt(1000) > BigInt(market.state.supplyAssets)) { - result.push(BAD_DEBT) + // Append bad debt warnings + try { + const badDebtUnderlying = market.realizedBadDebt.underlying; + if (badDebtUnderlying != null) { + const badDebt = BigInt(badDebtUnderlying); + if (badDebt > 0n) { + // only push the bad debt error is it's > 10BPS + const supplyAssets = BigInt(market.state.supplyAssets); + if (badDebt * 1000n > supplyAssets) { + result.push(BAD_DEBT); + } + } } + } catch { + // ignore invalid BigInt values (e.g., decimal strings like "0.00") } - // append our own oracle warnings + // Append our own oracle warnings const oracleType = getOracleType( market.oracle?.data, market.oracleAddress,