Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/api/balances/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const ALCHEMY_URLS = {
'1': `https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
'8453': `https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
'137': `https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
'130': `https://unichain-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}`,
};

type TokenBalance = {
Expand Down
5 changes: 3 additions & 2 deletions app/api/positions/historical/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async function getPositionAtBlock(
abi: morphoABI,
functionName: 'market',
args: [marketId as `0x${string}`],
blockNumber: BigInt(blockNumber),
blockNumber: isNow ? undefined : BigInt(blockNumber),
})) as readonly bigint[];

// Convert array to market object
Expand Down Expand Up @@ -129,6 +129,7 @@ async function getPositionAtBlock(
marketId,
userAddress,
blockNumber,
chainId,
error,
});
throw error;
Expand Down Expand Up @@ -159,7 +160,7 @@ export async function GET(request: NextRequest) {
position,
});
} catch (error) {
console.error('Error in historical position API:', error);
// console.error('Error', error);
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

Suppressed error logging may hinder debugging.

Commenting out the error logging removes useful debugging information. Consider keeping it or using a more selective logging approach.

-// console.error('Error', error);
+console.error('Error fetching historical position:', error);
📝 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
// console.error('Error', error);
console.error('Error fetching historical position:', error);
🤖 Prompt for AI Agents
In app/api/positions/historical/route.ts at line 167, the error logging is
commented out, which suppresses useful debugging information. Restore the error
logging by uncommenting the console.error statement or replace it with a more
selective logging method that captures and logs relevant error details without
overwhelming the logs.

return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"shikiji-core": "^0.9.17",
"tailwind-merge": "^2.5.5",
"unified": "^11.0.4",
"viem": "2.x",
"viem": "2.31.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify this viem version supports unichain and is current.

Pinning to a specific version is appropriate for ensuring unichain compatibility, but confirm this version has the latest security patches.


🌐 Web query:

What is the latest version of viem and does version 2.31.0 include unichain support?

💡 Result:

As of June 9, 2025, the latest version of the viem package is 2.23.12, published approximately two hours ago. (npmjs.com) Regarding version 2.31.0, there is no record of this release in the available sources. Additionally, the provided information does not specify whether viem includes support for Unichain. For the most accurate and up-to-date details, I recommend checking the official viem documentation or the package's repository.

Citations:


Validate and correct the pinned viem version

The version “2.31.0” isn’t published on npm (latest is 2.23.12 as of June 9, 2025). Pinning to a non-existent release will break installs and won’t guarantee Unichain support.

• Confirm which viem release actually introduces Unichain
• Update package.json to a valid version (e.g. ^2.23.12) or use a semver range that covers the required release
• Re-run installs to verify compatibility

🤖 Prompt for AI Agents
In package.json at line 73, the viem version is pinned to "2.31.0", which does
not exist on npm and will cause install failures. Verify which viem version
first supports Unichain, then update the version field to a valid published
version that includes this support, such as "^2.23.12" or an appropriate semver
range. After updating, run the package installation to confirm compatibility and
successful resolution.

"wagmi": "^2.10.2",
"workbox-webpack-plugin": "^7.0.0",
"zod": "^3.24.2"
Expand Down
1 change: 1 addition & 0 deletions src/contexts/MarketsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export function MarketsProvider({ children }: MarketsProviderProps) {
SupportedNetworks.Mainnet,
SupportedNetworks.Base,
SupportedNetworks.Polygon,
SupportedNetworks.Unichain
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify data source configuration for Unichain.

Adding Unichain to the fetch list is correct, but ensure the data source mapping is configured for this network.


🏁 Script executed:

#!/bin/bash
# Check if Unichain is configured in data source mappings
rg -A 5 -B 5 "Unichain|130" src/config/dataSources*

Length of output: 55


Let’s locate the data‐source config and check for Unichain mapping.


🏁 Script executed:

#!/bin/bash
# Find any dataSources config files
config_files=$(fd -e ts -i dataSources src/config)
echo "Config files:" $config_files

# Search each for Unichain or its network ID
for file in $config_files; do
  echo "Inspecting $file"
  rg -C3 'Unichain|130' "$file" || true
done

Length of output: 335


Missing Unichain entry in data‐source config

No SupportedNetworks.Unichain mapping was found in src/config/dataSources.ts. You’ll need to add a data-source configuration for Unichain, for example:

[SupportedNetworks.Unichain]: {
  // add Unichain’s endpoint, fetch logic, etc.
},
  • File: src/config/dataSources.ts
  • Action: Define the Unichain mapping to match other networks’ configurations.
🤖 Prompt for AI Agents
In src/config/dataSources.ts around the relevant network mappings, add a new
entry for SupportedNetworks.Unichain similar to other networks. Define its
endpoint, fetch logic, and any other required configuration properties to ensure
Unichain is properly supported as a data source. This will align with the usage
in src/contexts/MarketsContext.tsx line 81 and prevent missing configuration
errors.

];
let combinedMarkets: Market[] = [];
let fetchErrors: unknown[] = [];
Expand Down
4 changes: 3 additions & 1 deletion src/hooks/useUserBalances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ export function useUserBalances() {

try {
// Fetch balances from both chains
const [mainnetBalances, baseBalances, polygonBalances] = await Promise.all([
const [mainnetBalances, baseBalances, polygonBalances, unichainBalances] = await Promise.all([
fetchBalances(SupportedNetworks.Mainnet),
fetchBalances(SupportedNetworks.Base),
fetchBalances(SupportedNetworks.Polygon),
fetchBalances(SupportedNetworks.Unichain),
]);

// Process and filter tokens
Expand All @@ -79,6 +80,7 @@ export function useUserBalances() {
processTokens(mainnetBalances, 1);
processTokens(baseBalances, 8453);
processTokens(polygonBalances, 137);
processTokens(unichainBalances, 130);
setBalances(processedBalances);
} catch (err) {
setError(err instanceof Error ? err : new Error('Unknown error occurred'));
Expand Down
11 changes: 11 additions & 0 deletions src/imgs/chains/unichain.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/store/createWagmiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import {
} from '@rainbow-me/rainbowkit/wallets';
import { safe } from '@wagmi/connectors';
import { createConfig, http } from 'wagmi';
import { base, mainnet, polygon } from 'wagmi/chains';
import { base, mainnet, polygon, unichain } from 'wagmi/chains';
import { getChainsForEnvironment } from './supportedChains';

const alchemyKey = process.env.NEXT_PUBLIC_ALCHEMY_API_KEY;

const rpcMainnet = `https://eth-mainnet.g.alchemy.com/v2/${alchemyKey}`;
const rpcBase = `https://base-mainnet.g.alchemy.com/v2/${alchemyKey}`;
const rpcPolygon = `https://polygon-mainnet.g.alchemy.com/v2/${alchemyKey}`;
const rpcUnichain = `https://unichain-mainnet.g.alchemy.com/v2/${alchemyKey}`;

export function createWagmiConfig(projectId: string) {
const connectors = connectorsForWallets(
Expand Down Expand Up @@ -53,6 +54,7 @@ export function createWagmiConfig(projectId: string) {
[mainnet.id]: http(rpcMainnet),
[base.id]: http(rpcBase),
[polygon.id]: http(rpcPolygon),
[unichain.id]: http(rpcUnichain),
},
connectors: [
...connectors,
Expand Down
10 changes: 5 additions & 5 deletions src/store/supportedChains.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { base, Chain, mainnet, polygon } from 'viem/chains';
import { base, Chain, mainnet, polygon, unichain } from 'viem/chains';
import { Environment, getCurrentEnvironment } from './environment';

// The list of supported Chains for a given environment
export const SUPPORTED_CHAINS: Record<Environment, [Chain, ...Chain[]]> = {
[Environment.localhost]: [mainnet, base, polygon],
[Environment.development]: [mainnet, base, polygon],
[Environment.staging]: [mainnet, base, polygon],
[Environment.production]: [mainnet, base, polygon],
[Environment.localhost]: [mainnet, base, polygon, unichain],
[Environment.development]: [mainnet, base, polygon, unichain],
[Environment.staging]: [mainnet, base, polygon, unichain],
[Environment.production]: [mainnet, base, polygon, unichain],
};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/utils/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const getAssetURL = (address: string, chain: SupportedNetworks): string =
return `https://basescan.org/token/${address}`;
case SupportedNetworks.Polygon:
return `https://polygonscan.com/token/${address}`;
case SupportedNetworks.Unichain:
return `https://uniscan.xyz/token/${address}`;
default:
return `https://etherscan.io/token/${address}`;
}
Expand All @@ -22,6 +24,8 @@ export const getExplorerURL = (address: string, chain: SupportedNetworks): strin
return `https://basescan.org/address/${address}`;
case SupportedNetworks.Polygon:
return `https://polygonscan.com/address/${address}`;
case SupportedNetworks.Unichain:
return `https://uniscan.xyz/address/${address}`;
default:
return `https://etherscan.io/address/${address}`;
}
Expand All @@ -33,6 +37,8 @@ export const getExplorerTxURL = (hash: string, chain: SupportedNetworks): string
return `https://basescan.org/tx/${hash}`;
case SupportedNetworks.Polygon:
return `https://polygonscan.com/tx/${hash}`;
case SupportedNetworks.Unichain:
return `https://uniscan.xyz/tx/${hash}`;
default:
return `https://etherscan.io/tx/${hash}`;
}
Expand Down
10 changes: 9 additions & 1 deletion src/utils/morpho.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const getMorphoAddress = (chain: SupportedNetworks) => {
return '0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb';
case SupportedNetworks.Polygon:
return '0x1bf0c2541f820e775182832f06c0b7fc27a25f67';
case SupportedNetworks.Unichain:
return '0x8f5ae9cddb9f68de460c77730b018ae7e04a140a';
Comment on lines +18 to +19
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify the Morpho contract address for Unichain.

Please confirm that 0x8f5ae9cddb9f68de460c77730b018ae7e04a140a is the correct Morpho contract address on Unichain.


🌐 Web query:

What is the official Morpho protocol contract address on Unichain network?

💡 Result:

The official Morpho protocol contract address on the Unichain network is:

0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb[1].

This is the core Morpho protocol contract, as referenced in the official Morpho documentation listing contract addresses across supported networks, including new deployments on Unichain[1][6]. This address is widely referred to as the main Morpho contract, sometimes called "morpho-blue," and is used as the entry point for protocol interactions on Unichain.

For the most up-to-date and verified list of Morpho smart contract addresses, always consult the [Morpho Docs address resource][1].

Citations:


Update Unichain Morpho address & zero-pad genesis date

  • In src/utils/morpho.ts (getMorphoAddress), replace the Unichain contract address with the official one from Morpho docs.
  • In src/utils/morpho.ts (getMorphoGenesisDate), zero-pad the seconds field to two digits.
 src/utils/morpho.ts

 case SupportedNetworks.Unichain:
-  return '0x8f5ae9cddb9f68de460c77730b018ae7e04a140a';
+  return '0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb';

 // …
 export function getMorphoGenesisDate(network: SupportedNetworks): string {
   switch (network) {
     // …
     case SupportedNetworks.Unichain:
-      return '2024-06-10T12:30:6.000Z';
+      return '2024-06-10T12:30:06.000Z';
📝 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
case SupportedNetworks.Unichain:
return '0x8f5ae9cddb9f68de460c77730b018ae7e04a140a';
// src/utils/morpho.ts
export function getMorphoAddress(network: SupportedNetworks): string {
switch (network) {
// … other networks …
case SupportedNetworks.Unichain:
return '0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb';
// … other networks …
}
}
export function getMorphoGenesisDate(network: SupportedNetworks): string {
switch (network) {
// … other networks …
case SupportedNetworks.Unichain:
return '2024-06-10T12:30:06.000Z';
// … other networks …
}
}
🤖 Prompt for AI Agents
In src/utils/morpho.ts around lines 18 to 19, update the Morpho contract address
for the Unichain network by replacing the current address with the official one
from the Morpho documentation: 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb.
Additionally, in the getMorphoGenesisDate function within the same file, ensure
the seconds field is zero-padded to two digits for consistent formatting.

default:
return zeroAddress;
}
Expand All @@ -30,7 +32,8 @@ export const getBundlerV2 = (chain: SupportedNetworks) => {
case SupportedNetworks.Polygon:
// ChainAgnosticBundlerV2
return '0x5738366B9348f22607294007e75114922dF2a16A';

case SupportedNetworks.Unichain:
return '0x5738366B9348f22607294007e75114922dF2a16A';
default:
return zeroAddress;
}
Expand All @@ -44,6 +47,8 @@ export const getIRMTitle = (address: string) => {
return 'Adaptive Curve';
case '0xe675a2161d4a6e2de2eed70ac98eebf257fbf0b0': // on polygon
return 'Adaptive Curve';
case '0x9a6061d51743b31d2c3be75d83781fa423f53f0e': // on unichain
return 'Adaptive Curve';
default:
return 'Unknown IRM';
}
Expand All @@ -65,6 +70,7 @@ export const actionTypeToText = (type: UserTxTypes) => {
const MAINNET_GENESIS_DATE = new Date('2023-12-28T09:09:23.000Z');
const BASE_GENESIS_DATE = new Date('2024-05-03T13:40:43.000Z');
const POLYGON_GENESIS_DATE = new Date('2025-01-20T02:03:12.000Z');
const UNICHAIN_GENESIS_DATE = new Date('2025-02-18T02:03:6.000Z');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the invalid date format.

The seconds field should be zero-padded: 06 instead of 6.

-const UNICHAIN_GENESIS_DATE = new Date('2025-02-18T02:03:6.000Z');
+const UNICHAIN_GENESIS_DATE = new Date('2025-02-18T02:03:06.000Z');
📝 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
const UNICHAIN_GENESIS_DATE = new Date('2025-02-18T02:03:6.000Z');
const UNICHAIN_GENESIS_DATE = new Date('2025-02-18T02:03:06.000Z');
🤖 Prompt for AI Agents
In src/utils/morpho.ts at line 73, the date string used to create
UNICHAIN_GENESIS_DATE has an invalid format because the seconds field is not
zero-padded. Fix this by changing the seconds from '6' to '06' in the date
string to ensure proper parsing.


export function getMorphoGenesisDate(chainId: number): Date {
switch (chainId) {
Expand All @@ -74,6 +80,8 @@ export function getMorphoGenesisDate(chainId: number): Date {
return BASE_GENESIS_DATE;
case SupportedNetworks.Polygon:
return POLYGON_GENESIS_DATE;
case SupportedNetworks.Unichain:
return UNICHAIN_GENESIS_DATE;
default:
return MAINNET_GENESIS_DATE; // default to mainnet
}
Expand Down
6 changes: 6 additions & 0 deletions src/utils/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ enum SupportedNetworks {
Mainnet = 1,
Base = 8453,
Polygon = 137,
Unichain = 130,
}

const isSupportedChain = (chainId: number) => {
Expand Down Expand Up @@ -30,6 +31,11 @@ const networks = [
logo: require('../imgs/chains/polygon.png') as string,
name: 'Polygon',
},
{
network: SupportedNetworks.Unichain,
logo: require('../imgs/chains/unichain.svg') as string,
name: 'Unichain',
},
];

const getNetworkImg = (chainId: number) => {
Expand Down
12 changes: 11 additions & 1 deletion src/utils/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createPublicClient, http } from 'viem';
import { base, mainnet, polygon } from 'viem/chains';
import { base, mainnet, polygon, unichain } from 'viem/chains';
import { SupportedNetworks } from './networks';

// Initialize Alchemy clients for each chain
Expand All @@ -18,6 +18,11 @@ export const polygonClient = createPublicClient({
transport: http(`https://polygon-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`),
});

export const unichainClient = createPublicClient({
chain: unichain,
transport: http(`https://unichain-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`),
});

export const getClient = (chainId: SupportedNetworks) => {
switch (chainId) {
case SupportedNetworks.Mainnet:
Expand All @@ -26,6 +31,8 @@ export const getClient = (chainId: SupportedNetworks) => {
return baseClient;
case SupportedNetworks.Polygon:
return polygonClient;
case SupportedNetworks.Unichain:
return unichainClient;
default:
throw new Error(`Unsupported chainId: ${chainId}`);
}
Expand All @@ -35,18 +42,21 @@ export const BLOCK_TIME = {
[SupportedNetworks.Mainnet]: 12, // Ethereum mainnet: 12 seconds
[SupportedNetworks.Base]: 2, // Base: 2 seconds
[SupportedNetworks.Polygon]: 2, // Polygon: 2 seconds
[SupportedNetworks.Unichain]: 1, // Unichain: 2 seconds
} as const;

export const GENESIS_BLOCK = {
[SupportedNetworks.Mainnet]: 18883124, // Ethereum mainnet
[SupportedNetworks.Base]: 13977148, // Base
[SupportedNetworks.Polygon]: 66931042, // Polygon
[SupportedNetworks.Unichain]: 9139027, // Unichain
} as const;

export const LATEST_BLOCK_DELAY = {
[SupportedNetworks.Mainnet]: 0, // Ethereum mainnet
[SupportedNetworks.Base]: 20, // Base
[SupportedNetworks.Polygon]: 20, // Polygon
[SupportedNetworks.Unichain]: 20, // Unichain
};

type BlockResponse = {
Expand Down
5 changes: 5 additions & 0 deletions src/utils/subgraph-urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ const polygonSubgraphUrl = apiKey
? `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/EhFokmwryNs7qbvostceRqVdjc3petuD13mmdUiMBw8Y`
: undefined;

const unichainSubgraphUrl = apiKey
? `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/ESbNRVHte3nwhcHveux9cK4FFAZK3TTLc5mKQNtpYgmu`
: undefined;

// Map network IDs (from SupportedNetworks) to Subgraph URLs
export const SUBGRAPH_URLS: { [key in SupportedNetworks]?: string } = {
[SupportedNetworks.Base]: baseSubgraphUrl,
[SupportedNetworks.Mainnet]: mainnetSubgraphUrl,
[SupportedNetworks.Polygon]: polygonSubgraphUrl,
[SupportedNetworks.Unichain]: unichainSubgraphUrl,
};

export const getSubgraphUrl = (network: SupportedNetworks): string | undefined => {
Expand Down
10 changes: 7 additions & 3 deletions src/utils/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Chain, base, mainnet, polygon } from 'viem/chains';
import { Chain, base, mainnet, polygon, unichain } from 'viem/chains';
import { SupportedNetworks } from './networks';

export type SingleChainERC20Basic = {
Expand Down Expand Up @@ -52,6 +52,7 @@ const supportedTokens = [
{ chain: mainnet, address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' },
{ chain: base, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' },
{ chain: polygon, address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' },
{ chain: unichain, address: '0x078d782b760474a361dda0af3839290b0ef57ad6' },
],
peg: TokenPeg.USD,
},
Expand Down Expand Up @@ -205,7 +206,7 @@ const supportedTokens = [
networks: [
{ chain: mainnet, address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' },
{ chain: base, address: '0x4200000000000000000000000000000000000006' },

{ chain: unichain, address: '0x4200000000000000000000000000000000000006' },
// wrapped eth on polygon, defined here as it will not be interpreted as "WETH Contract"
// which is determined by isWETH function
// This is solely for displaying and linking to eth.
Expand Down Expand Up @@ -461,7 +462,10 @@ const supportedTokens = [
symbol: 'UNI',
img: require('../imgs/tokens/uni.webp') as string,
decimals: 18,
networks: [{ chain: mainnet, address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984' }],
networks: [
{ chain: mainnet, address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'},
{ chain: unichain, address: '0x8f187aa05619a017077f5308904739877ce9ea21'}
],
},
{
symbol: 'AERO',
Expand Down
Loading