Skip to content

feat: morpho api backup#149

Merged
antoncoding merged 4 commits intomasterfrom
feat/backup-sources
Jun 17, 2025
Merged

feat: morpho api backup#149
antoncoding merged 4 commits intomasterfrom
feat/backup-sources

Conversation

@antoncoding
Copy link
Copy Markdown
Owner

@antoncoding antoncoding commented Jun 16, 2025

Summary by CodeRabbit

  • New Features

    • Market and user data now automatically attempts to fetch from the Morpho API when available, with an automatic fallback to the Subgraph if Morpho API is unsupported or unavailable.
    • Market data, user positions, liquidations, historical data, borrows, supplies, and transactions benefit from this prioritized, resilient data fetching strategy.
    • Market data is refreshed automatically every 5 minutes.
  • Bug Fixes

    • Improved error handling and logging for all data fetch operations, ensuring better transparency and reliability.
  • Refactor

    • Streamlined data fetching logic across multiple areas to prioritize Morpho API with Subgraph as a fallback, removing reliance on single-source selection.
    • Minor formatting improvements for consistency.
    • Enhanced user position and transaction fetching with detailed fallback and error handling mechanisms.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jun 16, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
monarch ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 17, 2025 1:37pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 16, 2025

📝 Walkthrough

Walkthrough

The codebase now uses a prioritized fallback for fetching data: it tries the Morpho API first (if supported by the network), and if that fails, falls back to the Subgraph. This pattern is applied across all relevant hooks and contexts. Error handling and logging are improved, and some formatting tweaks were made.

Changes

File(s) Change Summary
app/market/[chainId]/[marketid]/content.tsx Added explicit error handling for async calls and standardized void usage on window.open.
src/config/dataSources.ts Added supportsMorphoApi function to check Morpho API support for networks; removed string-based data source functions.
src/contexts/MarketsContext.tsx Refactored to use Morpho API with Subgraph fallback; added periodic refresh and improved logging.
src/hooks/useLiquidations.ts Switched to Morpho API-first fallback for liquidations; improved error handling and logging.
src/hooks/useMarketBorrows.ts, src/hooks/useMarketSupplies.ts, src/hooks/useMarketLiquidations.ts Refactored to try Morpho API first, then Subgraph; removed dataSource from return, improved logging.
src/hooks/useMarketData.ts, src/hooks/useMarketHistoricalData.ts Updated to Morpho API-first fallback for market and historical data; removed dataSource logic.
src/hooks/useUserPosition.ts Implemented Morpho API-first fallback for user position fetches with detailed error logging.
src/hooks/useUserPositions.ts Refactored to use Morpho API-first fallback for user positions and market data; improved batching.
src/hooks/useUserTransactions.ts Changed to sequential Morpho API-first fallback for user transactions; unified error handling.
src/utils/tokens.ts Minor formatting: added trailing commas in UNI token network addresses.
src/data-sources/morpho-api/transactions.ts Disabled filtering by marketUniqueKeys in Morpho transactions fetch; no other logic changes.

Sequence Diagram(s)

sequenceDiagram
    participant UI
    participant Hook
    participant MorphoAPI
    participant Subgraph

    UI->>Hook: Request data (e.g., market, positions)
    alt Morpho API supported
        Hook->>MorphoAPI: Fetch data
        alt MorphoAPI success
            MorphoAPI-->>Hook: Return data
        else MorphoAPI fails
            Hook->>Subgraph: Fetch data
            Subgraph-->>Hook: Return data
        end
    else Morpho API not supported
        Hook->>Subgraph: Fetch data
        Subgraph-->>Hook: Return data
    end
    Hook-->>UI: Return final data
Loading

Possibly related PRs

Poem

When Morpho is ready, it leads the way,
If it stumbles, Subgraph saves the day.
Errors are logged, no secrets to hide,
Data flows gently, fallback as guide.
With commas in place and logic anew,
The code’s now robust—cheers to the crew!
🦋🔄

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Commit Unit Tests in branch feat/backup-sources
  • Post Copyable Unit Tests in Comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🔭 Outside diff range comments (1)
src/hooks/useMarketData.ts (1)

60-73: Snapshot numbers need string conversion

Market.state.* is typed as string. Assigning BigInt / bigint-like values straight from snapshot will break JSON serialisation and can crash React rendering in some browsers.

-            supplyAssets: snapshot.totalSupplyAssets,
-            supplyShares: snapshot.totalSupplyShares,
-            borrowAssets: snapshot.totalBorrowAssets,
-            borrowShares: snapshot.totalBorrowShares,
-            liquidityAssets: snapshot.liquidityAssets,
+            supplyAssets: snapshot.totalSupplyAssets.toString(),
+            supplyShares: snapshot.totalSupplyShares.toString(),
+            borrowAssets: snapshot.totalBorrowAssets.toString(),
+            borrowShares: snapshot.totalBorrowShares.toString(),
+            liquidityAssets: snapshot.liquidityAssets.toString(),
♻️ Duplicate comments (1)
src/hooks/useMarketBorrows.ts (1)

30-50: Same duplication note as in useMarketSupplies

The fetch-with-fallback code is identical. Re-use a shared helper to avoid drift.

🧹 Nitpick comments (7)
src/config/dataSources.ts (1)

32-43: Duplicate switch-statements – extract a constant instead

supportsMorphoApi, getMarketDataSource, and getHistoricalDataSource all hard-code the same network list. Keeping them in sync is error-prone.

-  switch (network) {
-    case SupportedNetworks.Mainnet:
-    case SupportedNetworks.Base:
-      return true;
-    default:
-      return false;
-  }
+  const MORPHO_API_NETWORKS = new Set([
+    SupportedNetworks.Mainnet,
+    SupportedNetworks.Base,
+  ]);
+  return MORPHO_API_NETWORKS.has(network);

This removes repetition and makes later extensions single-source.

app/market/[chainId]/[marketid]/content.tsx (1)

134-137: Redundant .catch

handleRefreshAll already catches and logs; the extra .catch here never fires unless the call itself throws synchronously. That can’t happen. Dropping it simplifies the wrapper.

-  void handleRefreshAll().catch((error) => {
-    console.error('Failed to refresh data:', error);
-  });
+  void handleRefreshAll();
src/hooks/useMarketSupplies.ts (1)

30-47: Extract the fallback pattern into a shared util

The Morpho-first / Subgraph-fallback block appears in every new hook. Copy-pasted logic is harder to keep in sync (retry count, logging, etc.). Consider a helper like await fetchWithFallback({primary, fallback}) to DRY things up.

src/hooks/useMarketData.ts (1)

37-47: Guard supportsMorphoApi once

You already wrap the Morpho call in a try, so an unsupported network is not exceptional. Instead of an if + try you could:

try {
  if (supportsMorphoApi(network)) {
    finalMarket = await fetchMorphoMarket(uniqueKey, network);
  }
} catch { /* ... */ }

Simpler flow, one less indentation level.

src/hooks/useUserPosition.ts (1)

88-109: Factor out duplicated fallback code

The Morpho→Subgraph fallback logic is repeated three times in this hook alone. A small helper returning Promise<T | null> would shrink this file and make future changes (timeout, retry) one-liner updates.

src/contexts/MarketsContext.tsx (1)

189-197: Consider making the refresh interval configurable.

The 5-minute interval is reasonable but could be made configurable for different deployment scenarios.

+  // Could be passed as prop or from config
+  const REFRESH_INTERVAL_MS = 5 * 60 * 1000;
+
   // Set up refresh interval
   const refreshInterval = setInterval(
     () => {
       void fetchMarkets(true).catch(console.error);
     },
-    5 * 60 * 1000,
+    REFRESH_INTERVAL_MS,
   ); // Refresh every 5 minutes
src/hooks/useUserPositions.ts (1)

193-216: Consider extracting the fallback pattern to a shared utility.

Since this Morpho-first, Subgraph-fallback pattern is used across multiple hooks, consider creating a generic utility function.

Would you like me to create a generic fallback utility that can be reused across all these hooks?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdf5294 and 76497c2.

📒 Files selected for processing (13)
  • app/market/[chainId]/[marketid]/content.tsx (2 hunks)
  • src/config/dataSources.ts (1 hunks)
  • src/contexts/MarketsContext.tsx (6 hunks)
  • src/hooks/useLiquidations.ts (2 hunks)
  • src/hooks/useMarketBorrows.ts (2 hunks)
  • src/hooks/useMarketData.ts (4 hunks)
  • src/hooks/useMarketHistoricalData.ts (2 hunks)
  • src/hooks/useMarketLiquidations.ts (2 hunks)
  • src/hooks/useMarketSupplies.ts (2 hunks)
  • src/hooks/useUserPosition.ts (2 hunks)
  • src/hooks/useUserPositions.ts (4 hunks)
  • src/hooks/useUserTransactions.ts (4 hunks)
  • src/utils/tokens.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
app/market/[chainId]/[marketid]/content.tsx (1)
src/utils/external.ts (1)
  • getMarketURL (3-6)
src/config/dataSources.ts (1)
src/utils/networks.ts (1)
  • SupportedNetworks (52-52)
src/hooks/useMarketBorrows.ts (4)
src/utils/types.ts (1)
  • MarketActivityTransaction (378-384)
src/config/dataSources.ts (1)
  • supportsMorphoApi (35-43)
src/data-sources/morpho-api/market-borrows.ts (1)
  • fetchMorphoMarketBorrows (32-64)
src/data-sources/subgraph/market-borrows.ts (1)
  • fetchSubgraphMarketBorrows (31-84)
src/hooks/useMarketLiquidations.ts (4)
src/utils/types.ts (1)
  • MarketLiquidationTransaction (387-395)
src/config/dataSources.ts (1)
  • supportsMorphoApi (35-43)
src/data-sources/morpho-api/market-liquidations.ts (1)
  • fetchMorphoMarketLiquidations (31-68)
src/data-sources/subgraph/market-liquidations.ts (1)
  • fetchSubgraphMarketLiquidations (41-91)
src/hooks/useLiquidations.ts (3)
src/config/dataSources.ts (1)
  • supportsMorphoApi (35-43)
src/data-sources/morpho-api/liquidations.ts (1)
  • fetchMorphoApiLiquidatedMarketKeys (56-119)
src/data-sources/subgraph/liquidations.ts (1)
  • fetchSubgraphLiquidatedMarketKeys (20-76)
src/hooks/useMarketData.ts (3)
src/config/dataSources.ts (1)
  • supportsMorphoApi (35-43)
src/data-sources/morpho-api/market.ts (1)
  • fetchMorphoMarket (45-57)
src/data-sources/subgraph/market.ts (1)
  • fetchSubgraphMarket (296-326)
src/hooks/useMarketSupplies.ts (4)
src/utils/types.ts (1)
  • MarketActivityTransaction (378-384)
src/config/dataSources.ts (1)
  • supportsMorphoApi (35-43)
src/data-sources/morpho-api/market-supplies.ts (1)
  • fetchMorphoMarketSupplies (33-73)
src/data-sources/subgraph/market-supplies.ts (1)
  • fetchSubgraphMarketSupplies (33-96)
src/hooks/useUserTransactions.ts (4)
src/config/dataSources.ts (1)
  • supportsMorphoApi (35-43)
src/utils/types.ts (1)
  • UserTransaction (29-41)
src/data-sources/morpho-api/transactions.ts (1)
  • fetchMorphoTransactions (14-68)
src/data-sources/subgraph/transactions.ts (1)
  • fetchSubgraphTransactions (125-208)
🔇 Additional comments (4)
src/utils/tokens.ts (1)

466-468: Trailing comma change is fine

Pure formatting – no impact on code paths.

src/contexts/MarketsContext.tsx (2)

93-119: Good fallback implementation!

The two-step fallback pattern with detailed logging provides resilience and transparency.


81-81: Verify Unichain support in data sources.

Ensure that Unichain is properly supported in either Morpho API or Subgraph before adding it to the fetch list.

#!/bin/bash
# Check if Unichain is supported in supportsMorphoApi function
ast-grep --pattern 'supportsMorphoApi = $_($$$) => {
  $$$
}'

# Check for Unichain references in data source configurations
rg -A 5 "Unichain" src/config/ src/data-sources/
src/hooks/useUserPositions.ts (1)

108-134: Nice abstraction of the fallback pattern!

The fetchMarketData helper cleanly encapsulates the Morpho-first, Subgraph-fallback pattern.

Comment thread app/market/[chainId]/[marketid]/content.tsx
Comment thread src/hooks/useMarketLiquidations.ts
Comment on lines +50 to 59
// If Morpho API failed or not supported, try Subgraph
if (!historicalData) {
try {
console.log(`Attempting to fetch historical data via Subgraph for ${uniqueKey}`);
historicalData = await fetchSubgraphMarketHistoricalData(uniqueKey, network, options);
} catch (subgraphError) {
console.error(`Failed to fetch historical data via Subgraph:`, subgraphError);
historicalData = null;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Same silent-failure pattern as liquidations hook

If both sources fail we swallow the exception, error is unset, and consumers think data is just empty. Please propagate the last error (or aggregate both). Returning null vs empty structure also forces extra guarding code later.

Replicate the fix shown in useMarketLiquidations.

🤖 Prompt for AI Agents
In src/hooks/useMarketHistoricalData.ts around lines 50 to 59, the code silently
swallows errors when both Morpho API and Subgraph fetches fail, leaving the
error unset and causing consumers to misinterpret the data as simply empty.
Modify the code to propagate the last caught error (or combine errors if both
fail) instead of setting historicalData to null, ensuring the error state is
properly communicated to consumers, similar to the fix applied in
useMarketLiquidations.

Comment on lines +36 to 59
// Try Morpho API first if supported
if (supportsMorphoApi(network)) {
try {
console.log(`Attempting to fetch liquidated markets via Morpho API for ${network}`);
networkLiquidatedKeys = await fetchMorphoApiLiquidatedMarketKeys(network);
} catch (morphoError) {
console.error(`Failed to fetch liquidated markets via Morpho API:`, morphoError);
// Continue to Subgraph fallback
networkLiquidatedKeys = new Set();
}
} else {
console.warn(`No valid data source found for network ${network} for liquidations.`);
networkLiquidatedKeys = new Set<string>(); // Assume none if no source
networkLiquidatedKeys = new Set();
}

// If Morpho API failed or not supported, try Subgraph
if (networkLiquidatedKeys.size === 0) {
try {
console.log(`Attempting to fetch liquidated markets via Subgraph for ${network}`);
networkLiquidatedKeys = await fetchSubgraphLiquidatedMarketKeys(network);
} catch (subgraphError) {
console.error(`Failed to fetch liquidated markets via Subgraph:`, subgraphError);
throw subgraphError; // Throw to be caught by outer catch
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Uninitialised variable risk

let networkLiquidatedKeys: Set<string>; is declared but may stay undefined if both data sources throw.
Using const networkLiquidatedKeys = new Set<string>(); at declaration avoids the extra else { new Set() } and the possible undefined dereference later.

🤖 Prompt for AI Agents
In src/hooks/useLiquidations.ts around lines 36 to 59, the variable
networkLiquidatedKeys is declared without initialization and may remain
undefined if both Morpho API and Subgraph fetches fail, risking undefined
dereference. To fix this, initialize networkLiquidatedKeys as an empty
Set<string> at declaration using const, then update it as needed. This removes
the need for else blocks assigning new Sets and ensures networkLiquidatedKeys is
always defined.

Comment thread src/hooks/useUserTransactions.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/data-sources/morpho-api/transactions.ts (1)

61-67: Return typed errors instead of string fall-backs

err may be unknown. Converting to Error here keeps type safety and preserves stack traces.

-    return {
-      items: [],
-      pageInfo: { count: 0, countTotal: 0 },
-      error: err instanceof Error ? err.message : 'Unknown Morpho API error occurred',
-    };
+    const message =
+      err instanceof Error ? err.message : JSON.stringify(err);
+    return {
+      items: [],
+      pageInfo: { count: 0, countTotal: 0 },
+      error: message,
+    };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76497c2 and d99820c.

📒 Files selected for processing (3)
  • src/config/dataSources.ts (1 hunks)
  • src/data-sources/morpho-api/transactions.ts (1 hunks)
  • src/hooks/useUserTransactions.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/config/dataSources.ts
  • src/hooks/useUserTransactions.ts

Comment on lines +24 to +27
// disable cuz it's too long
// if (filters.marketUniqueKeys && filters.marketUniqueKeys.length > 0) {
// whereClause.marketUniqueKey_in = filters.marketUniqueKeys;
// }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Ignoring marketUniqueKeys drops an expected filter

filters.marketUniqueKeys is still accepted by callers but silently discarded.
Down-stream code that relies on this filter will now process extra markets, which can blow up payload size and break UI assumptions.

Options:

-// disable cuz it's too long
-// if (filters.marketUniqueKeys && filters.marketUniqueKeys.length > 0) {
-//   whereClause.marketUniqueKey_in = filters.marketUniqueKeys;
-// }
+// Morpho API rejects very long `IN` arrays (~5 KB limit). Chunk and merge.
+if (filters.marketUniqueKeys?.length) {
+  const CHUNK = 50;
+  const chunks = [];
+  for (let i = 0; i < filters.marketUniqueKeys.length; i += CHUNK) {
+    chunks.push({ ...whereClause, marketUniqueKey_in: filters.marketUniqueKeys.slice(i, i + CHUNK) });
+  }
+  return mergeResponses(
+    await Promise.all(chunks.map((w) => query(w)))
+  );
+}

If the size limit is the real reason, chunking or a server-side alias is safer than dropping the filter.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// disable cuz it's too long
// if (filters.marketUniqueKeys && filters.marketUniqueKeys.length > 0) {
// whereClause.marketUniqueKey_in = filters.marketUniqueKeys;
// }
// Morpho API rejects very long `IN` arrays (~5 KB limit). Chunk and merge.
if (filters.marketUniqueKeys?.length) {
const CHUNK = 50;
const chunks = [];
for (let i = 0; i < filters.marketUniqueKeys.length; i += CHUNK) {
chunks.push({
...whereClause,
marketUniqueKey_in: filters.marketUniqueKeys.slice(i, i + CHUNK),
});
}
return mergeResponses(
await Promise.all(chunks.map((w) => query(w)))
);
}
🤖 Prompt for AI Agents
In src/data-sources/morpho-api/transactions.ts around lines 24 to 27, the code
currently ignores the filters.marketUniqueKeys filter by commenting it out,
which causes unexpected behavior downstream. To fix this, re-enable the filter
logic for marketUniqueKeys and implement a solution to handle large arrays
safely, such as chunking the filter values into smaller batches or using a
server-side alias to limit the size, ensuring the filter is applied without
causing payload or UI issues.

@antoncoding antoncoding merged commit 6610189 into master Jun 17, 2025
4 checks passed
@antoncoding antoncoding deleted the feat/backup-sources branch June 17, 2025 13:51
@coderabbitai coderabbitai Bot mentioned this pull request Aug 18, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Nov 25, 2025
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.

1 participant