Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughAdds an Autovault feature (pages, UI, deployment flow, hooks, subgraph data, and factory ABI), narrows the balances API to supported tokens, removes Monarch agent / rebalancer UI and related props, refactors onboarding and positions flows for multi-network balances, and includes multiple minor styling/formatting edits. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant AV as AutovaultPage/AutovaultContent
participant DM as DeploymentModal
participant DC as DeploymentContext
participant CV as useCreateVault
participant W as Wallet/Chain
participant F as VaultV2Factory
participant SG as Subgraph
U->>AV: Open Autovault page
U->>AV: Click "Create Autovault"
AV->>DM: show DeploymentModal
DM->>DC: select token + network
alt need chain switch
DC->>W: switchToNetwork()
W-->>DC: success/error
end
U->>DM: confirm Deploy
DM->>DC: createVault()
DC->>CV: encode & send createVaultV2 tx
CV->>W: sendTransaction
W->>F: tx executes -> event newVaultV2
W-->>CV: tx success
CV-->>DC: deploy complete
AV->>SG: fetchUserVaultsV2AllNetworks(owner)
SG-->>AV: return vaults
sequenceDiagram
autonumber
participant P as /autovault/[vaultAddress] page
participant VC as VaultContent
participant H as useVaultDetails
participant U as User
P->>VC: mount with vaultAddress
VC->>H: fetch vault details
alt loading
VC-->>U: Header + LoadingScreen
else not found/error
VC-->>U: Vault Not Found + Back link
else success
VC-->>U: Overview, Performance, Agents
alt user is owner & toggles settings
U->>VC: toggle Settings
VC-->>U: VaultSettings panel shown
else
VC-->>U: Analytics placeholder
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
src/utils/positions.ts (1)
377-407: Regression: zero-share positions now lostThe pre-filter removes every position with zero
supplyShares, so entries that only carry historical earnings never reachshouldInclude. Previously those market rows still surfaced because we checkedgetEarningsForPeriodbefore deciding. Now they disappear from the UI, which is a functional regression. Please drop the upfront filter and rely on the existing inclusion guard inside the reducer.- return positions - .filter((position) => BigInt(position.state.supplyShares) > 0) - .reduce((acc: GroupedPosition[], position) => { + return positions + .reduce((acc: GroupedPosition[], position) => {scripts/generate-chainlink-data.ts (1)
118-121: Fix ESM entry-point check (require is undefined under tsx/ESM).
requireisn’t available in ESM; this will crash when run viatsx. Switch to animport.meta.urlcheck.Apply this diff:
-if (require.main === module) { - main(); -} +// ESM-safe main check +if (import.meta.url === pathToFileURL(process.argv[1]).href) { + void main(); +}Also add the import at the top of the file:
+import { pathToFileURL } from 'url';src/hooks/useUserRebalancerInfo.ts (1)
27-58: Make per-network requests resilient; handle non-OK responses.One failing fetch rejects the whole
Promise.all. Also missingresponse.okcheck.Apply this diff:
- const promises = agentNetworks.map(async (networkId) => { + const results = await Promise.allSettled(agentNetworks.map(async (networkId) => { const apiUrl = getMonarchAgentUrl(networkId); if (!apiUrl) return null; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query: userRebalancerInfoQuery, variables: { id: account.toLowerCase() }, }), }); - const json = (await response.json()) as { data?: { user?: UserRebalancerInfo } }; + if (!response.ok) { + throw new Error(`HTTP ${response.status} on ${networkId}`); + } + const json = (await response.json()) as { data?: { user?: UserRebalancerInfo } }; if (json.data?.user) { return { ...json.data.user, network: networkId, } as UserRebalancerInfo; } return null; - }); - - const results = await Promise.all(promises); - const validResults = results.filter( - (result): result is UserRebalancerInfo => result !== null, - ); + })); + const validResults = results + .filter((r): r is PromiseFulfilledResult<UserRebalancerInfo | null> => r.status === 'fulfilled') + .map(r => r.value) + .filter((v): v is UserRebalancerInfo => v !== null);src/utils/subgraph-urls.ts (1)
33-39: Fix TS typing (values may be undefined) and align naming.You’re assigning possibly undefined URLs into a
Partial<Record<..., string>>, which expectsstring(notstring | undefined). This can fail type-checking. Also, keeparbitrumvar naming consistent with others.Apply:
-const arbitrumSubgraph = apiKey +const arbitrumSubgraphUrl = apiKey ? `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/XsJn88DNCHJ1kgTqYeTgHMQSK4LuG1LR75339QVeQ26` : undefined; -// Map network IDs (from SupportedNetworks) to Subgraph URLs -export const SUBGRAPH_URLS: Partial<Record<SupportedNetworks, string>> = { +// Map network IDs (from SupportedNetworks) to Subgraph URLs +export const SUBGRAPH_URLS: Record<SupportedNetworks, string | undefined> = { [SupportedNetworks.Base]: baseSubgraphUrl, [SupportedNetworks.Mainnet]: mainnetSubgraphUrl, [SupportedNetworks.Polygon]: polygonSubgraphUrl, [SupportedNetworks.Unichain]: unichainSubgraphUrl, - [SupportedNetworks.Arbitrum]: arbitrumSubgraph, + [SupportedNetworks.Arbitrum]: arbitrumSubgraphUrl, };Also applies to: 28-31
app/positions/components/onboarding/SetupPositions.tsx (1)
41-47: Filter balances by chain ID.
useUserBalancesAllNetworksreturns entries for every network. Matching only onaddresswill grab the first hit—tokens like WETH live at0x4200…on both Base and Optimism—so the UI can show or use the wrong balance and let users submit transactions that must revert. Please include the network/chain discriminator in the predicate before converting toBigInt(adjust the property name if it differs).Apply this diff:
- const tokenBalance = useMemo(() => { - if (!selectedToken) return 0n; - return BigInt( - balances.find((b) => b.address.toLowerCase() === selectedToken.address.toLowerCase()) - ?.balance ?? '0', - ); - }, [balances, selectedToken]); + const tokenBalance = useMemo(() => { + if (!selectedToken) return 0n; + + const match = balances.find( + (b) => + b.address.toLowerCase() === selectedToken.address.toLowerCase() && + b.chainId === selectedToken.network, + ); + + return BigInt(match?.balance ?? '0'); + }, [balances, selectedToken]);
🧹 Nitpick comments (25)
src/utils/monarch-agent.ts (1)
30-36: Deduplicate shared agent metadata.
Line 32 repeats the v1 entry; when details change we’ll need to touch both spots. Consider buildingv2AgentsBasefromagentsso the data stays in sync.-export const v2AgentsBase: AgentMetadata[] = [ - { - name: 'Max APY Agent', - address: KnownAgents.MAX_APY, - strategyDescription: 'Rebalance every 8 hours, always move to the highest APY', - }, -]; +export const v2AgentsBase: AgentMetadata[] = agents.map((agent) => ({ ...agent }));scripts/generate-chainlink-data.ts (2)
48-51: Don’t mutate input; localize the hotfix. Also fix typos in the comment.Avoid mutating
entry.docs. Compute a local override and use it in the return.-// this data entry is coorupted as teh time we generate -if (entry.proxyAddress === '0x0D03E26E0B5D09E24E5a45696D0FcA12E9648FBB') { - entry.docs.quoteAsset = 'USD'; -} +// this data entry is corrupted at the time we generate +const forcedQuote = + entry.proxyAddress === '0x0D03E26E0B5D09E24E5a45696D0FcA12E9648FBB' ? 'USD' : undefined; ... - quoteAsset: entry.docs?.quoteAsset ?? '', + quoteAsset: forcedQuote ?? entry.docs?.quoteAsset ?? '',Also applies to: 61-63
100-111: Fetch networks concurrently and tolerate partial failures.Current loop aborts everything on one failure and is sequential.
try { - const networks = Object.keys(ENDPOINTS) as Array<keyof typeof ENDPOINTS>; - - for (const network of networks) { - const cleanData = await fetchAndProcessData(network); - writeJsonFile(network, cleanData); - } + const networks = Object.keys(ENDPOINTS) as Array<keyof typeof ENDPOINTS>; + const results = await Promise.allSettled(networks.map(fetchAndProcessData)); + results.forEach((res, i) => { + const network = networks[i]; + if (res.status === 'fulfilled') { + writeJsonFile(network, res.value); + } else { + console.error(`Failed ${network}:`, res.reason); + } + });app/autovault/components/deployment/DeploymentContext.tsx (1)
45-52: Avoid defaulting to mainnet before a selection.Passing
1can show a false “need switch” state. Default to the current chain.- const { needSwitchChain, switchToNetwork } = useMarketNetwork({ - targetChainId: selectedTokenAndNetwork?.networkId ?? 1, - }); + const { needSwitchChain, switchToNetwork } = useMarketNetwork({ + targetChainId: selectedTokenAndNetwork?.networkId ?? currentChainId, + });Add the import and var:
-import { useAccount } from 'wagmi'; +import { useAccount, useChainId } from 'wagmi'; ... - const { address: account } = useAccount(); + const { address: account } = useAccount(); + const currentChainId = useChainId();src/hooks/useAutovaultData.ts (1)
75-77: Use address-safe equality.Lowercasing works, but
isAddressEqualavoids edge cases.- const ownedVaults = mockData.filter( - (vault) => vault.owner.toLowerCase() === account.toLowerCase(), - ); + const ownedVaults = mockData.filter( + (vault) => isAddressEqual(vault.owner, account), + );Add import:
-import { Address } from 'viem'; +import { Address, isAddressEqual } from 'viem';src/utils/subgraph-urls.ts (2)
15-18: Remove stale TODO.You’ve already filled a real Mainnet subgraph ID; drop the TODO to avoid confusion.
-// TODO: Replace 'YOUR_MAINNET_SUBGRAPH_ID' with the actual Mainnet Subgraph ID
6-9: Avoid import-time console.error in browser.This runs on import (client and server). Consider downgrading to warn or logging only server-side.
-if (!apiKey) { - console.error('NEXT_PUBLIC_THEGRAPH_API_KEY is not set in environment variables.'); - // Potentially throw an error or handle this case as needed -} +if (!apiKey && typeof window === 'undefined') { + console.warn('NEXT_PUBLIC_THEGRAPH_API_KEY missing; subgraph URLs will be undefined.'); +}app/api/balances/route.ts (1)
20-25: Harden token selection and zero-balance handling; short‑circuit empty lists.
- Dedupe/normalize addresses per chain.
- Avoid RPC call when no supported tokens.
- Filter zeros via BigInt, not string equality (more robust).
Apply:
try { - const alchemyUrl = DEFAULT_RPC_URLS[Number(chainId) as SupportedNetworks]; + const chainIdNum = Number(chainId); + const alchemyUrl = DEFAULT_RPC_URLS[chainIdNum as SupportedNetworks]; if (!alchemyUrl) { throw new Error(`Chain ${chainId} not supported`); } - // Get supported token addresses for this chain - const tokenAddresses = supportedTokens - .filter(token => - token.networks.some(network => network.chain.id === Number(chainId)) - ) - .flatMap(token => - token.networks - .filter(network => network.chain.id === Number(chainId)) - .map(network => network.address) - ); + // Get supported token addresses for this chain (deduped, lowercased) + const tokenAddresses = Array.from( + new Set( + supportedTokens.flatMap((token) => + token.networks + .filter((n) => n.chain.id === chainIdNum) + .map((n) => n.address.toLowerCase()), + ), + ), + ); - // Get token balances for specific tokens only + // No supported tokens -> empty result + if (tokenAddresses.length === 0) { + return NextResponse.json({ tokens: [] }); + } + // Get token balances for specific tokens only const balancesResponse = await fetch(alchemyUrl, { @@ - method: 'alchemy_getTokenBalances', - params: [address, tokenAddresses], + method: 'alchemy_getTokenBalances', + params: [address, tokenAddresses], }), }); @@ - const nonZeroBalances: TokenBalance[] = balancesData.result.tokenBalances.filter( - (token: TokenBalance) => - token.tokenBalance !== '0x0000000000000000000000000000000000000000000000000000000000000000', - ); - - // Filter out failed metadata requests - const tokens = nonZeroBalances - .filter((token) => token !== null) - .map((token) => ({ - address: token.contractAddress.toLowerCase(), - balance: BigInt(token.tokenBalance).toString(10), - })); + // Keep only non-zero balances (robust to different hex zero formats) + const tokens = balancesData.result.tokenBalances.flatMap((t) => { + try { + const bal = BigInt(t.tokenBalance); + return bal > 0n + ? [{ address: t.contractAddress.toLowerCase(), balance: bal.toString(10) }] + : []; + } catch { + return []; // skip malformed entries + } + });Also applies to: 26-35, 37-38, 48-49, 64-75
app/autovault/[vaultAddress]/page.tsx (1)
5-10: Make metadata dynamic for per‑vault SEO (optional).If you want OG/title to reflect the vault, switch to route
generateMetadataand alias the util to avoid a name clash.-import { generateMetadata } from '@/utils/generateMetadata'; +import { generateMetadata as buildMetadata } from '@/utils/generateMetadata'; @@ -export const metadata = generateMetadata({ - title: 'Vault Details | Monarch', - description: 'Detailed information about a specific autovault', - images: 'themes.png', - pathname: '', -}); +export async function generateMetadata({ params }: { params: { vaultAddress: string } }) { + const { vaultAddress } = params; + return buildMetadata({ + title: `Vault ${vaultAddress.slice(0, 6)}… | Monarch`, + description: 'Detailed information about a specific autovault', + images: 'themes.png', + pathname: `/autovault/${vaultAddress}`, + }); +}Also applies to: 1-1
src/utils/tokens.ts (1)
631-641: Avoid hard‑coded WETH by chain; centralize addresses.Keeps logic in one place and mirrors SupportedNetworks explicitly.
Apply within this function:
-const isWETH = (address: string, chainId: number) => { - if (chainId === SupportedNetworks.Mainnet) { - return address.toLowerCase() === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; - } - if (chainId === SupportedNetworks.Base || chainId === SupportedNetworks.Unichain) { - return address.toLowerCase() === '0x4200000000000000000000000000000000000006'; - } - - if (chainId === SupportedNetworks.Arbitrum) { - return address.toLowerCase() === '0x82af49447d8a07e3bd95bd0d56f35241523fbab1'; - } - return false; -}; +const isWETH = (address: string, chainId: number) => { + const WETH_BY_CHAIN: Record<number, string> = { + [SupportedNetworks.Mainnet]: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + [SupportedNetworks.Base]: '0x4200000000000000000000000000000000000006', + [SupportedNetworks.Unichain]: '0x4200000000000000000000000000000000000006', + [SupportedNetworks.Arbitrum]: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', + }; + const target = WETH_BY_CHAIN[chainId]; + return target ? address.toLowerCase() === target : false; +};app/positions/components/onboarding/AssetSelection.tsx (2)
57-59: Rename to avoid shadowing and improve readability.Use a distinct name for metadata lookup.
- const token = findToken(balance.address, balance.chainId) - if (!token) return; + const tokenMeta = findToken(balance.address, balance.chainId); + if (!tokenMeta) return;
60-70: Prefer canonical token metadata for symbol/decimals and add logo fallback.Prevents mismatches across networks and missing icons.
- result.push({ - symbol: balance.symbol, + result.push({ + symbol: tokenMeta.symbol ?? balance.symbol, markets: relevantMarkets, minApy, maxApy, - logoURI: token.img, - decimals: balance.decimals, + logoURI: tokenMeta.img ?? undefined, + decimals: tokenMeta.decimals ?? balance.decimals, network, address: balance.address, balance: balance.balance, });src/abis/vaultv2factory.ts (2)
1-1: Import type‑only.Saves bytes and matches TS best practice.
-import { Abi } from "viem"; +import type { Abi } from "viem";
3-3: Name the ABI and keep literal types.Avoid a generic
abiexport and keep literal types withsatisfies Abifor better viem inference.-export const abi = [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"},{"indexed":true,"internalType":"address","name":"newVaultV2","type":"address"}],"name":"CreateVaultV2","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"createVaultV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isVaultV2","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"vaultV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] as Abi +export const vaultV2FactoryAbi = [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"},{"indexed":true,"internalType":"address","name":"newVaultV2","type":"address"}],"name":"CreateVaultV2","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"createVaultV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isVaultV2","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"vaultV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] as const satisfies Abiapp/autovault/[vaultAddress]/components/VaultSettings.tsx (1)
5-10: Propvaultis unused.Either display contextual info (name/status) or drop the prop for now to avoid dead API.
app/autovault/components/deployment/TokenSelection.tsx (5)
24-35: Don’t duplicate NetworkIcon; reuse the shared component.There’s already a common
NetworkIconatsrc/components/common/NetworkIcon.tsx. Import and drop this local copy.-import { getNetworkImg, SupportedNetworks } from '@/utils/networks'; +import { isSupportedChain, getNetworkImg } from '@/utils/networks'; +import { NetworkIcon } from '@/components/common/NetworkIcon'; @@ -function NetworkIcon({ networkId }: { networkId: number }) { - const url = getNetworkImg(networkId); - return ( - <Image - src={url as string} - alt={`networkId-${networkId}`} - width={16} - height={16} - className="rounded-full" - /> - ); -}
47-49: Stale closure risk: depend onfindToken(and trim unused state).
useMemousesfindTokenbut it’s not in deps;allTokensisn’t used. Depend onfindTokenand dropallTokens.- const { allTokens, findToken } = useTokens() + const { findToken } = useTokens(); @@ - }, [balances, allTokens, whitelistedMarkets]); + }, [balances, whitelistedMarkets, findToken]);Also applies to: 95-95
62-66: Prefer an explicit supported‑chain check; avoid no‑op cast.Casting to
SupportedNetworksthen checking truthiness adds no value. UseisSupportedChainto mirror how other modules gate networks. Based on learnings.- const network = balance.chainId as SupportedNetworks const balanceValue = balance.balance ? BigInt(balance.balance) : 0n; - if (network && balanceValue > 0n) { + if (isSupportedChain(balance.chainId) && balanceValue > 0n) {
88-95: Sorting via Number can lose precision for large balances.Compare as integers scaled to a common decimal to keep full precision.
- return tokenNetworks.sort((a, b) => { - const aBalance = Number(formatUnits(a.balance, a.decimals)); - const bBalance = Number(formatUnits(b.balance, b.decimals)); - if (bBalance !== aBalance) return bBalance - aBalance; - return a.symbol.localeCompare(b.symbol); - }); + return tokenNetworks.sort((a, b) => { + const maxDec = Math.max(a.decimals, b.decimals); + const aScaled = a.balance * (10n ** BigInt(maxDec - a.decimals)); + const bScaled = b.balance * (10n ** BigInt(maxDec - b.decimals)); + if (aScaled !== bScaled) return aScaled > bScaled ? -1 : 1; + return a.symbol.localeCompare(b.symbol); + });
178-185: Tiny a11y polish (optional).Consider adding
aria-pressed={isSelected}on the button container andaria-labelon the selection row for better screen‑reader feedback.src/utils/networks.ts (2)
60-62: Use networks[] as the source of truth for support check.
Object.valueson a numeric enum includes string keys; safer to check againstnetworks.-const isSupportedChain = (chainId: number) => { - return Object.values(SupportedNetworks).includes(chainId); -}; +const isSupportedChain = (chainId: number) => { + return networks.some((n) => n.network === chainId); +};
68-73: Clarify agent availability semantics.Right now availability == has
subgraphEndpoint. If the UI assumes “can deploy & manage,” consider also requiring a factory address and at least one strategy.- return network.vaultConfig.subgraphEndpoint !== undefined + return Boolean( + network.vaultConfig.subgraphEndpoint && + network.vaultConfig.v2FactoryAddress && + (network.vaultConfig.strategies?.length ?? 0) > 0 + );If you intend “read-only vault listing,” keep current logic. Please confirm.
src/hooks/useUserBalances.ts (3)
58-70: Early returns toggle loading off but never on.If
fetchAllBalancesis called whileloadingis true from a previous run, early returns won’t reset it to true for subsequent calls. Minor, but can cause flicker. Guard with a consistent state path.- const fetchAllBalances = useCallback(async () => { + const fetchAllBalances = useCallback(async () => { if (!address) { setBalances([]); setLoading(false); return; } if (networksToFetch.length === 0) { setBalances([]); setLoading(false); return; } - setLoading(true); + setLoading(true);No behavior change; just a note to keep call sites aware.
74-112: Ignore stale responses on rapid address/network changes.Race: multiple in‑flight requests can set state out of order. Track a request id and bail if obsolete.
+// add near other hooks +// const latestReq = useRef(0); @@ - try { + try { + // const reqId = ++latestReq.current; // Fetch balances from specified networks only const balancePromises = networksToFetch.map(async (chainId) => fetchBalances(chainId)); const networkBalances = await Promise.all(balancePromises); + // if (reqId !== latestReq.current) return; // stale @@ - setBalances(processedBalances); + // if (reqId !== latestReq.current) return; // stale + setBalances(processedBalances);If you want, I can wire this fully (including the
useRef) in a tiny follow‑up.
35-40: Deps for networksToFetch.
isAgentAvailableornetworkswon’t usually change, but for correctness include them (or document the assumption).- }, [options.networkIds]); + }, [options.networkIds, isAgentAvailable]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (53)
app/api/balances/route.ts(3 hunks)app/autovault/[vaultAddress]/components/VaultSettings.tsx(1 hunks)app/autovault/[vaultAddress]/content.tsx(1 hunks)app/autovault/[vaultAddress]/page.tsx(1 hunks)app/autovault/components/AutovaultContent.tsx(1 hunks)app/autovault/components/VaultListV2.tsx(1 hunks)app/autovault/components/deployment/DeploymentContext.tsx(1 hunks)app/autovault/components/deployment/DeploymentModal.tsx(1 hunks)app/autovault/components/deployment/TokenSelection.tsx(1 hunks)app/autovault/page.tsx(1 hunks)app/market/[chainId]/[marketid]/components/CampaignBadge.tsx(2 hunks)app/market/[chainId]/[marketid]/components/CampaignModal.tsx(2 hunks)app/market/[chainId]/[marketid]/components/PositionStats.tsx(3 hunks)app/positions/components/PositionsContent.tsx(0 hunks)app/positions/components/PositionsSummaryTable.tsx(1 hunks)app/positions/components/onboarding/AssetSelection.tsx(3 hunks)app/positions/components/onboarding/Modal.tsx(3 hunks)app/positions/components/onboarding/OnboardingContext.tsx(1 hunks)app/positions/components/onboarding/RiskSelection.tsx(4 hunks)app/positions/components/onboarding/SetupPositions.tsx(5 hunks)app/positions/components/onboarding/SuccessPage.tsx(2 hunks)scripts/generate-chainlink-data.ts(4 hunks)src/abis/vaultv2factory.ts(1 hunks)src/components/Input/Input.tsx(1 hunks)src/components/SupplyModalContent.tsx(1 hunks)src/components/TokenIcon.tsx(1 hunks)src/components/layout/header/Navbar.tsx(1 hunks)src/components/providers/TokenProvider.tsx(3 hunks)src/config/dataSources.ts(1 hunks)src/constants/oracle/chainlink-data/arbitrum.json(1 hunks)src/constants/oracle/chainlink-data/base.json(1 hunks)src/constants/oracle/chainlink-data/index.ts(2 hunks)src/constants/oracle/chainlink-data/mainnet.json(1 hunks)src/constants/oracle/chainlink-data/polygon.json(1 hunks)src/contexts/MarketsContext.tsx(1 hunks)src/data-sources/subgraph/v2-vaults.ts(1 hunks)src/graphql/morpho-v2-subgraph-queries.ts(1 hunks)src/hooks/useAutovaultData.ts(1 hunks)src/hooks/useCreateVault.ts(1 hunks)src/hooks/useLiquidations.ts(1 hunks)src/hooks/useUserBalances.ts(5 hunks)src/hooks/useUserRebalancerInfo.ts(2 hunks)src/hooks/useUserVaultsV2.ts(1 hunks)src/store/createWagmiConfig.ts(2 hunks)src/utils/erc20.ts(1 hunks)src/utils/external.ts(5 hunks)src/utils/monarch-agent.ts(1 hunks)src/utils/morpho.ts(1 hunks)src/utils/networks.ts(4 hunks)src/utils/positions.ts(2 hunks)src/utils/rpc.ts(2 hunks)src/utils/subgraph-urls.ts(1 hunks)src/utils/tokens.ts(5 hunks)
💤 Files with no reviewable changes (1)
- app/positions/components/PositionsContent.tsx
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2024-12-16T02:01:51.219Z
Learnt from: antoncoding
PR: antoncoding/monarch#97
File: app/positions/components/onboarding/OnboardingContext.tsx:36-43
Timestamp: 2024-12-16T02:01:51.219Z
Learning: In `app/positions/components/onboarding/OnboardingContext.tsx`, the `defaultStep` variable is no longer needed and can be removed.
Applied to files:
app/positions/components/onboarding/Modal.tsxapp/positions/components/onboarding/SuccessPage.tsxapp/positions/components/onboarding/OnboardingContext.tsx
📚 Learning: 2024-12-17T10:51:07.277Z
Learnt from: antoncoding
PR: antoncoding/monarch#99
File: src/components/AgentSetupProcessModal.tsx:38-51
Timestamp: 2024-12-17T10:51:07.277Z
Learning: In `src/components/AgentSetupProcessModal.tsx`, the modal is intentionally designed without a close button.
Applied to files:
app/positions/components/onboarding/Modal.tsxapp/positions/components/onboarding/SuccessPage.tsx
📚 Learning: 2024-12-17T12:39:21.949Z
Learnt from: antoncoding
PR: antoncoding/monarch#99
File: app/positions/components/onboarding/SuccessPage.tsx:17-17
Timestamp: 2024-12-17T12:39:21.949Z
Learning: Prefer using explicit network checks like `selectedToken?.network === SupportedNetworks.Base` over using array indexing like `config.agentSupportedNetworks[0]` for better maintainability.
Applied to files:
src/utils/rpc.tssrc/hooks/useLiquidations.tssrc/hooks/useUserBalances.tsapp/positions/components/onboarding/AssetSelection.tsxapp/autovault/components/deployment/TokenSelection.tsxsrc/utils/networks.ts
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
PR: antoncoding/monarch#63
File: app/markets/components/MarketRowDetail.tsx:49-52
Timestamp: 2024-10-12T09:23:16.495Z
Learning: When rendering oracle feeds in `ExpandedMarketDetail` (`app/markets/components/MarketRowDetail.tsx`), prefer explicit rendering over iterating keys when dealing with a small number of feeds.
Applied to files:
app/positions/components/onboarding/RiskSelection.tsx
🧬 Code graph analysis (29)
app/autovault/components/deployment/DeploymentModal.tsx (6)
app/autovault/components/deployment/DeploymentContext.tsx (2)
useDeployment(89-95)DeploymentProvider(39-87)src/hooks/useUserBalances.ts (1)
useUserBalances(26-124)src/contexts/MarketsContext.tsx (1)
useMarkets(269-275)src/components/common/Button.tsx (1)
Button(4-53)app/autovault/components/deployment/TokenSelection.tsx (1)
TokenSelection(44-196)src/components/common/Spinner.tsx (1)
Spinner(24-57)
src/components/providers/TokenProvider.tsx (1)
src/utils/rpc.ts (1)
CHAIN_CONFIGS(17-23)
app/autovault/page.tsx (2)
app/autovault/[vaultAddress]/page.tsx (1)
metadata(5-10)app/autovault/components/AutovaultContent.tsx (1)
AutovaultContent(13-86)
src/data-sources/subgraph/v2-vaults.ts (3)
src/utils/networks.ts (4)
SupportedNetworks(91-91)getAgentConfig(96-96)networks(97-97)isAgentAvailable(98-98)src/data-sources/subgraph/fetchers.ts (1)
subgraphGraphqlFetcher(1-31)src/graphql/morpho-v2-subgraph-queries.ts (1)
userVaultsV2Query(3-14)
src/store/createWagmiConfig.ts (2)
src/utils/rpc.ts (1)
DEFAULT_RPC_URLS(8-14)src/hooks/useCustomRpc.ts (1)
CustomRpcUrls(5-11)
src/utils/rpc.ts (1)
src/utils/networks.ts (1)
SupportedNetworks(91-91)
app/autovault/components/deployment/DeploymentContext.tsx (2)
src/hooks/useMarketNetwork.ts (1)
useMarketNetwork(39-69)src/hooks/useCreateVault.ts (1)
useCreateVault(22-102)
app/positions/components/PositionsSummaryTable.tsx (1)
src/utils/positions.ts (1)
groupPositionsByLoanAsset(373-452)
app/autovault/[vaultAddress]/components/VaultSettings.tsx (2)
src/hooks/useAutovaultData.ts (1)
AutovaultData(18-37)src/components/common/Button.tsx (1)
Button(4-53)
app/positions/components/onboarding/SuccessPage.tsx (1)
src/components/common/Button.tsx (1)
Button(4-53)
src/components/TokenIcon.tsx (1)
src/components/TooltipContent.tsx (1)
TooltipContent(12-39)
app/market/[chainId]/[marketid]/components/CampaignBadge.tsx (1)
src/components/common/Badge.tsx (1)
Badge(31-33)
src/hooks/useCreateVault.ts (2)
src/hooks/useStyledToast.tsx (1)
useStyledToast(6-20)src/hooks/useTransactionWithToast.tsx (1)
useTransactionWithToast(20-114)
app/positions/components/onboarding/SetupPositions.tsx (5)
src/hooks/useUserBalances.ts (1)
useUserBalancesAllNetworks(136-140)src/hooks/useLocalStorage.ts (1)
useLocalStorage(4-78)src/components/Input/Input.tsx (1)
Input(17-97)src/components/TokenIcon.tsx (1)
TokenIcon(15-58)app/markets/components/APYBreakdownTooltip.tsx (1)
APYCell(72-97)
src/hooks/useUserBalances.ts (2)
src/utils/networks.ts (3)
SupportedNetworks(91-91)networks(97-97)isAgentAvailable(98-98)src/components/providers/TokenProvider.tsx (1)
useTokens(132-138)
app/autovault/components/AutovaultContent.tsx (4)
src/hooks/useUserVaultsV2.ts (1)
useUserVaultsV2(14-76)src/components/common/Button.tsx (1)
Button(4-53)app/autovault/components/VaultListV2.tsx (1)
VaultListV2(15-113)app/autovault/components/deployment/DeploymentModal.tsx (1)
DeploymentModal(92-98)
app/positions/components/onboarding/AssetSelection.tsx (2)
src/hooks/useUserBalances.ts (1)
useUserBalancesAllNetworks(136-140)src/utils/tokens.ts (1)
findToken(655-655)
src/hooks/useUserVaultsV2.ts (2)
src/data-sources/subgraph/v2-vaults.ts (2)
UserVaultV2(22-25)fetchUserVaultsV2AllNetworks(83-94)src/utils/erc20.ts (1)
getERC20Balance(5-30)
app/autovault/[vaultAddress]/content.tsx (5)
src/hooks/useAutovaultData.ts (1)
useVaultDetails(121-180)src/components/Status/LoadingScreen.tsx (1)
LoadingScreen(10-22)src/components/common/Button.tsx (1)
Button(4-53)src/components/common/AddressDisplay.tsx (1)
AddressDisplay(14-43)app/autovault/[vaultAddress]/components/VaultSettings.tsx (1)
VaultSettings(10-176)
src/utils/subgraph-urls.ts (1)
src/utils/networks.ts (1)
SupportedNetworks(91-91)
app/positions/components/onboarding/RiskSelection.tsx (4)
app/markets/components/MarketTableUtils.tsx (1)
TDAsset(40-72)src/utils/balance.ts (2)
formatReadable(25-46)formatBalance(21-23)app/markets/components/APYBreakdownTooltip.tsx (1)
APYCell(72-97)app/markets/components/RiskIndicator.tsx (3)
MarketAssetIndicator(127-147)MarketOracleIndicator(149-169)MarketDebtIndicator(171-191)
src/utils/external.ts (1)
src/utils/networks.ts (2)
SupportedNetworks(91-91)getNetworkName(94-94)
app/autovault/components/VaultListV2.tsx (7)
src/data-sources/subgraph/v2-vaults.ts (1)
UserVaultV2(22-25)src/components/providers/TokenProvider.tsx (1)
useTokens(132-138)src/components/common/Spinner.tsx (1)
Spinner(24-57)src/utils/tokens.ts (1)
findToken(655-655)src/utils/networks.ts (1)
getNetworkImg(93-93)src/utils/balance.ts (1)
formatReadable(25-46)src/components/TokenIcon.tsx (1)
TokenIcon(15-58)
src/utils/monarch-agent.ts (1)
src/utils/types.ts (1)
AgentMetadata(358-362)
app/autovault/components/deployment/TokenSelection.tsx (9)
src/components/common/NetworkIcon.tsx (1)
NetworkIcon(4-15)src/utils/networks.ts (2)
getNetworkImg(93-93)SupportedNetworks(91-91)src/hooks/useUserBalances.ts (1)
TokenBalance(6-13)src/utils/types.ts (1)
Market(260-305)app/autovault/components/deployment/DeploymentContext.tsx (1)
SelectedToken(15-20)src/components/providers/TokenProvider.tsx (1)
useTokens(132-138)src/components/common/Spinner.tsx (1)
Spinner(24-57)src/components/TokenIcon.tsx (1)
TokenIcon(15-58)src/utils/balance.ts (1)
formatReadable(25-46)
src/utils/tokens.ts (1)
src/utils/networks.ts (1)
SupportedNetworks(91-91)
src/utils/erc20.ts (1)
src/utils/rpc.ts (1)
getClient(73-84)
app/autovault/[vaultAddress]/page.tsx (2)
app/autovault/page.tsx (1)
metadata(5-10)app/autovault/[vaultAddress]/content.tsx (1)
VaultContent(17-218)
src/utils/networks.ts (2)
src/utils/types.ts (1)
AgentMetadata(358-362)src/utils/monarch-agent.ts (1)
v2AgentsBase(30-36)
🔇 Additional comments (16)
src/utils/morpho.ts (1)
46-57: Consistent return formatting.Matching the other cases with an explicit semicolon keeps the section tidy.
app/market/[chainId]/[marketid]/components/PositionStats.tsx (3)
33-39: Zero-balance check stays solidLogic is unchanged and reads cleaner.
50-52: Initial view mode selection looks rightState still defaults to user view only when a position exists.
207-209: Whitespace tweak keeps APY display intactNo behavioral change; formatting stays correct.
app/market/[chainId]/[marketid]/components/CampaignModal.tsx (2)
53-54: Symbol label formatting is fine.Switch to double quotes keeps render identical.
107-109: Map block unchanged functionally.Only spacing moved; behavior stays the same.
app/market/[chainId]/[marketid]/components/CampaignBadge.tsx (1)
35-39: Button styling tweak is safe.Reordered classes and compact badge markup still render the same content.
src/components/Input/Input.tsx (1)
86-94: Explicit guard keeps button gating clear.Thanks for making the condition explicit; matches the rest of the component logic.
src/components/TokenIcon.tsx (1)
37-43: Tooltip styling change looks good.Custom
classNameskeeps the wrapper neutral and letsTooltipContentown the visuals. No issues spotted.app/autovault/page.tsx (1)
5-10: Metadata setup LGTM.Assuming
generateMetadatahandles emptypathnamefor/autovault. If not, pass it explicitly.src/graphql/morpho-v2-subgraph-queries.ts (1)
5-13: Fix GraphQL field name and variable type
- Rename
createVaultV2Sto match the schema’s collection name (e.g.createVaultV2s).- Update the
$ownervariable fromString!toBytes!if the schema definesowner: Bytes!.app/autovault/[vaultAddress]/page.tsx (1)
12-14: LGTM on page composition.Simple pass‑through to content is fine.
src/utils/tokens.ts (1)
56-56: Token map tweaks look good.Trailing commas/formatting + Arbitrum entries for USDC/WBTC/MORPHO and syrupUSDC one‑liner are fine.
Also applies to: 286-286, 451-451, 579-580
app/positions/components/onboarding/AssetSelection.tsx (2)
41-45: Good explicit network + address match.Filtering markets by
chain.idand token address is clear and safe.Based on learnings
143-155: Verify APY units and balance type.
- Confirm
market.state.supplyApyis a fraction (0.05) before multiplying by 100; otherwise you’ll show 100x.- Ensure
balance.balanceis string/number;BigInt(<bigint>)is fine but double‑check the upstream type to avoid surprises.app/autovault/[vaultAddress]/components/VaultSettings.tsx (1)
169-173: Close action wiring looks correct.
onPressmatches the shared Button component.
Summary by CodeRabbit