Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds per-address vault fetching, deployment phases with address capture and navigation, vault indexing with polling/toasts, transaction grouping and history preview, initialization metadata step (name/symbol), and broad UI/state refactors across autovault list/detail, allocation tables, and history components. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant DeployModal as Deployment Modal
participant DeployCtx as Deployment Context
participant RPC as Blockchain (publicClient/contract)
participant Router as Router
participant Storage as LocalStorage
User->>DeployModal: Click "Deploy"
DeployModal->>DeployCtx: createVault(asset)
activate DeployCtx
DeployCtx->>DeployCtx: set phase='deploying'
DeployCtx->>RPC: send transaction
RPC-->>DeployCtx: tx receipt (CreateVaultV2 event)
DeployCtx->>DeployCtx: decode event → vaultAddress
DeployCtx->>Storage: addDeployedVault(vaultAddress, chainId, owner?)
DeployCtx->>DeployCtx: set deployedVaultAddress, set phase='success'
deactivate DeployCtx
DeployModal->>User: show success modal
User->>DeployModal: Click "Start Setup"
DeployModal->>DeployCtx: navigateToVault()
DeployCtx->>Router: route to /vault/{vaultAddress}
sequenceDiagram
actor User
participant InitModal as Vault Initialization Modal
participant IndexStore as vault-indexing.ts (localStorage)
participant Poller as useVaultIndexing hook
participant Subgraph as Subgraph/API
participant Toast as Toasts
User->>InitModal: Complete deploy step
InitModal->>IndexStore: startVaultIndexing(address, chainId)
InitModal->>Poller: start polling
loop every 5s
Poller->>Subgraph: refetch adapter/market data
Subgraph-->>Poller: not indexed yet
Poller->>Toast: ensure "Indexing..." toast shown
end
Subgraph-->>Poller: adapter detected/indexed
Poller->>Toast: clear indexing toast, show success
Poller->>InitModal: auto-advance to next step (metadata)
sequenceDiagram
participant API as Transactions API
participant Grouper as transactionGrouping.ts
participant History as HistoryTable
participant User
API->>Grouper: fetch user transactions
Grouper->>Grouper: group by tx.hash
Grouper->>Grouper: classify group (rebalance/deposits/withdrawals/unknown)
Grouper-->>History: groupedTransactions[]
History->>User: render grouped rows (expandable rebalance details)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/autovault/components/vault-detail/settings/EditCaps.tsx (1)
183-222: Missing adapter cap change detection.The
hasChangescheck doesn't account for adapter cap updates. If the adapter is not authorized (or partially authorized) and the user hasn't modified any market or collateral caps, the Save button stays disabled even thoughhandleSavewould update the adapter cap. This prevents users from fixing the adapter authorization without making unrelated changes.🔎 Proposed fix
const hasChanges = useMemo(() => { + // Check for adapter cap changes + if (adapterAddress && existingCaps) { + const targetRelativeCap = parseUnits('100', 16); + const targetAbsoluteCap = maxUint128; + const currentRelativeCap = existingCaps.adapterCap ? BigInt(existingCaps.adapterCap.relativeCap) : 0n; + const currentAbsoluteCap = existingCaps.adapterCap ? BigInt(existingCaps.adapterCap.absoluteCap) : 0n; + + if (currentRelativeCap !== targetRelativeCap || currentAbsoluteCap !== targetAbsoluteCap) { + return true; + } + } + // Check for new caps const hasNewMarkets = Array.from(marketCaps.values()).some((m) => !m.existingCapId); const hasNewCollaterals = Array.from(collateralCaps.values()).some((c) => !c.existingCapId); // ... rest of the checks
🧹 Nitpick comments (10)
src/components/layout/header/Navbar.tsx (1)
96-101: Autovault link correctly hidden for soft launch.The change aligns with the PR objective. If the Autovault feature won't be re-enabled soon, consider removing the commented code instead of leaving it in place—version control preserves the history.
src/features/markets/components/markets-table-same-loan.tsx (2)
894-896: Remove unused variable.The
_selectedMarketsvariable is computed but never referenced. This appears to be a leftover from the cart removal.🔎 Proposed fix
- const _selectedMarkets = useMemo(() => { - return markets.filter((m) => m.isSelected); - }, [markets]); -
57-57: Remove unused prop.The
renderCartItemExtraprop is defined but never used in the component. Clean this up as part of the cart removal.🔎 Proposed fix
disabled?: boolean; - // Optional: Render additional content for selected markets in the cart - renderCartItemExtra?: (market: Market) => React.ReactNode; // Optional: Pass unique tokens for better filter performanceAnd remove from the function signature:
export function MarketsTableWithSameLoanAsset({ markets, onToggleMarket, disabled = false, - renderCartItemExtra, uniqueCollateralTokens,src/features/autovault/components/vault-detail/settings/EditCaps.tsx (1)
237-257: Redundant condition check.Line 238 checks
if (adapterAddress)but lines 230-233 already verifyadapterAddressexists and return early if not. This condition will always be true at this point.🔎 Simplification
const capsToUpdate: VaultV2Cap[] = []; // Add or fix adapter cap to ensure it's always 100% relative + maxUint128 absolute - if (adapterAddress) { - const targetRelativeCap = parseUnits('100', 16); - const targetAbsoluteCap = maxUint128; + const targetRelativeCap = parseUnits('100', 16); + const targetAbsoluteCap = maxUint128; - const currentRelativeCap = existingCaps?.adapterCap ? BigInt(existingCaps.adapterCap.relativeCap) : 0n; - const currentAbsoluteCap = existingCaps?.adapterCap ? BigInt(existingCaps.adapterCap.absoluteCap) : 0n; + const currentRelativeCap = existingCaps?.adapterCap ? BigInt(existingCaps.adapterCap.relativeCap) : 0n; + const currentAbsoluteCap = existingCaps?.adapterCap ? BigInt(existingCaps.adapterCap.absoluteCap) : 0n; - // Only update if not already at target values - if (currentRelativeCap !== targetRelativeCap || currentAbsoluteCap !== targetAbsoluteCap) { - const { params, id } = getAdapterCapId(adapterAddress); - capsToUpdate.push({ - capId: id, - idParams: params, - relativeCap: targetRelativeCap.toString(), - absoluteCap: targetAbsoluteCap.toString(), - oldRelativeCap: currentRelativeCap.toString(), - oldAbsoluteCap: currentAbsoluteCap.toString(), - }); - } + // Only update if not already at target values + if (currentRelativeCap !== targetRelativeCap || currentAbsoluteCap !== targetAbsoluteCap) { + const { params, id } = getAdapterCapId(adapterAddress); + capsToUpdate.push({ + capId: id, + idParams: params, + relativeCap: targetRelativeCap.toString(), + absoluteCap: targetAbsoluteCap.toString(), + oldRelativeCap: currentRelativeCap.toString(), + oldAbsoluteCap: currentAbsoluteCap.toString(), + }); }src/features/home/home-view.tsx (1)
314-377: Remove commented-out code.Section 4 is entirely commented out. Since version control preserves this code in history, remove it to keep the file clean and maintainable.
🔎 Proposed fix
- {/* Section 4: Auto Vaults - Full Screen, Center Layout, No Image */} - {/* <section className="flex min-h-screen w-full items-center bg-main py-16 md:py-24"> - <div className="container mx-auto px-6"> - <div className="mx-auto max-w-3xl text-center"> - <div className="mb-6 flex items-center justify-center gap-3"> - <h2 className="font-zen text-4xl text-primary"> - Auto Vaults - </h2> - <Badge variant="success" size="lg"> - New - </Badge> - </div> - <p className="mb-8 text-2xl text-secondary"> - Be Your Own Risk Curator - </p> - - <div className="space-y-8"> - <p className="text-xl leading-relaxed text-secondary"> - Deploy your own vault. Define your risk parameters. Keep full control. - </p> - - <div className="space-y-6 text-left"> - <div className="flex items-start gap-4"> - <span className="font-zen text-3xl text-monarch-orange">1</span> - <div> - <h4 className="mb-2 font-zen text-xl text-primary">Deploy Your Vault</h4> - <p className="text-lg text-secondary"> - Launch your own vault contract with just a few clicks. No technical expertise required. - </p> - </div> - </div> - - <div className="flex items-start gap-4"> - <span className="font-zen text-3xl text-monarch-orange">2</span> - <div> - <h4 className="mb-2 font-zen text-xl text-primary">Full Control</h4> - <p className="text-lg text-secondary"> - Set your own risk parameters, choose markets, define caps. You're the curator. No performance fees, no middlemen. - </p> - </div> - </div> - - <div className="flex items-start gap-4"> - <span className="font-zen text-3xl text-monarch-orange">3</span> - <div> - <h4 className="mb-2 font-zen text-xl text-primary">Automated Optimization</h4> - <p className="text-lg text-secondary"> - Choose automation agents that work within your rules to optimize yields automatically. - </p> - </div> - </div> - </div> - </div> - - <div className="mt-12"> - <Link href="/autovault"> - <Button variant="primary" size="lg" className="px-12 py-4 font-zen"> - Create Auto Vault - </Button> - </Link> - </div> - </div> - </div> - </section> */} -src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (1)
265-276: Polling continues after modal closes.This is intentional per the comment at line 307, but the polling runs for 30 seconds after init. The unmount cleanup at lines 312-319 handles this, which is good.
One issue: if the component unmounts before
postInitPollingRef.currentis assigned (rare race), the interval won't be cleared. Consider assigning to a local variable first.Safer interval assignment
// Poll every 3 seconds for up to 30 seconds (10 attempts) let attempts = 0; const maxAttempts = 10; - postInitPollingRef.current = setInterval(() => { + const intervalId = setInterval(() => { attempts++; void onAdapterConfigured(); - if (attempts >= maxAttempts && postInitPollingRef.current) { - clearInterval(postInitPollingRef.current); + if (attempts >= maxAttempts) { + clearInterval(intervalId); postInitPollingRef.current = null; } }, 3000); + postInitPollingRef.current = intervalId;src/features/autovault/vault-list-view.tsx (2)
95-100: Use Next.js router for navigation.Direct
window.location.hrefcauses a full page reload. UseuseRouterfromnext/navigationfor client-side navigation.Use Next.js router
+'use client'; + +import { useRouter } from 'next/navigation'; // ... other imports export default function AutovaultListContent() { + const router = useRouter(); // ... other code const handleManageVault = () => { if (vaultAddresses.length > 0) { const firstVault = vaultAddresses[0]; - window.location.href = `/autovault/${firstVault.networkId}/${firstVault.address}`; + router.push(`/autovault/${firstVault.networkId}/${firstVault.address}`); } };
71-81: Silent error handling.Errors are logged but users get no feedback. Consider showing a toast or error state.
src/data-sources/morpho-api/v2-vaults.ts (1)
122-146: Per-address fetching can be noisy and hit rate limits.Parallel
Promise.allwith many addresses may trigger API rate limiting. Theconsole.logat line 138 will spam logs for every missing vault.Consider:
- Adding request batching/throttling for large address lists
- Downgrading the log to
console.debugor removing itQuieter logging
const vault = response.data?.vaultV2ByAddress; if (!vault) { - console.log(`No V2 vault found for address ${address} on network ${network}`); + // Vault not indexed yet or doesn't exist - this is expected for new vaults return null; }src/features/autovault/components/deployment/deployment-context.tsx (1)
146-150: Usingwindow.location.hrefcauses full page reload.Next.js apps typically use
useRouter().push()for client-side navigation. Full reload loses app state and is slower.Use Next.js router
+import { useRouter } from 'next/navigation'; export function DeploymentProvider({ children }: { children: React.ReactNode }) { + const router = useRouter(); // ... const navigateToVault = useCallback(() => { if (deployedVaultAddress && selectedTokenAndNetwork) { - window.location.href = `/autovault/${selectedTokenAndNetwork.networkId}/${deployedVaultAddress}`; + router.push(`/autovault/${selectedTokenAndNetwork.networkId}/${deployedVaultAddress}`); } - }, [deployedVaultAddress, selectedTokenAndNetwork]); + }, [deployedVaultAddress, selectedTokenAndNetwork, router]);
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (21)
src/components/layout/header/Navbar.tsxsrc/components/layout/header/NavbarMobile.tsxsrc/data-sources/morpho-api/v2-vaults.tssrc/features/autovault/components/deployment/deployment-context.tsxsrc/features/autovault/components/deployment/deployment-modal.tsxsrc/features/autovault/components/deployment/token-selection.tsxsrc/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsxsrc/features/autovault/components/vault-detail/settings/EditCaps.tsxsrc/features/autovault/components/vault-detail/vault-allocator-card.tsxsrc/features/autovault/components/vault-detail/vault-collaterals-card.tsxsrc/features/autovault/components/vault-detail/vault-market-allocations.tsxsrc/features/autovault/vault-list-view.tsxsrc/features/autovault/vault-view.tsxsrc/features/home/home-view.tsxsrc/features/markets/components/markets-table-same-loan.tsxsrc/features/positions/components/onboarding/market-selection-onboarding.tsxsrc/graphql/morpho-api-queries.tssrc/hooks/useVaultPage.tssrc/hooks/useVaultV2.tssrc/hooks/useVaultV2Data.tssrc/utils/monarch-agent.ts
💤 Files with no reviewable changes (2)
- src/hooks/useVaultV2Data.ts
- src/features/positions/components/onboarding/market-selection-onboarding.tsx
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.
Applied to files:
src/features/autovault/vault-list-view.tsxsrc/features/autovault/components/deployment/deployment-modal.tsxsrc/features/autovault/vault-view.tsx
📚 Learning: 2024-12-17T12:39:21.949Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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/features/autovault/components/deployment/token-selection.tsx
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/markets/components/markets-table-same-loan.tsx
📚 Learning: 2024-12-16T02:01:51.219Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/markets/components/markets-table-same-loan.tsxsrc/components/layout/header/NavbarMobile.tsx
📚 Learning: 2025-12-09T10:06:43.810Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:43.810Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. Usage: const { address, chainId, isConnected } = useConnection() from 'wagmi'.
Applied to files:
src/features/autovault/components/deployment/deployment-context.tsx
📚 Learning: 2024-12-17T10:51:07.277Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
📚 Learning: 2025-12-09T10:06:39.848Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:39.848Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. In your code under src/hooks, use: const { address, chainId, isConnected } = useConnection() from 'wagmi' to access the connected wallet information.
Applied to files:
src/hooks/useVaultPage.tssrc/hooks/useVaultV2.ts
🧬 Code graph analysis (8)
src/features/autovault/vault-list-view.tsx (2)
src/data-sources/subgraph/v2-vaults.ts (1)
fetchUserVaultV2AddressesAllNetworks(83-92)src/components/ui/button.tsx (1)
Button(107-107)
src/features/autovault/components/vault-detail/settings/EditCaps.tsx (1)
src/utils/morpho.ts (1)
getAdapterCapId(112-121)
src/features/autovault/components/deployment/deployment-modal.tsx (2)
src/utils/networks.ts (2)
ALL_SUPPORTED_NETWORKS(38-46)isAgentAvailable(203-208)src/features/autovault/components/deployment/deployment-context.tsx (1)
useDeployment(199-205)
src/features/autovault/components/deployment/deployment-context.tsx (1)
src/data-sources/subgraph/v2-vaults.ts (1)
fetchUserVaultV2Addresses(38-78)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (2)
src/components/ui/spinner.tsx (1)
Spinner(22-58)src/hooks/useStyledToast.tsx (1)
useStyledToast(6-38)
src/features/autovault/vault-view.tsx (2)
src/components/shared/tooltip-content.tsx (1)
TooltipContent(16-71)src/features/autovault/components/vault-detail/vault-collaterals-card.tsx (1)
VaultCollateralsCard(19-84)
src/data-sources/morpho-api/v2-vaults.ts (2)
src/data-sources/morpho-api/fetchers.ts (1)
morphoGraphqlFetcher(4-28)src/graphql/morpho-api-queries.ts (1)
vaultV2Query(538-574)
src/features/home/home-view.tsx (1)
src/components/ui/button.tsx (1)
Button(107-107)
🔇 Additional comments (29)
src/components/layout/header/NavbarMobile.tsx (1)
106-112: Mobile navigation updated consistently.The Autovault item is hidden in the mobile dropdown, matching the desktop navbar change.
src/utils/monarch-agent.ts (1)
28-28: LGTM!Description update reflecting the new 4-hour rebalance cadence.
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (3)
79-124: LGTM!MetadataStep is clean. Good use of
maxLength={16}on symbol to prevent overly long symbols.
321-341: Polling effect looks correct.Cleanup properly clears the interval when dependencies change or on unmount. The 5-second interval is reasonable for adapter detection.
390-403: Validation is minimal.Only checks non-empty after trim. Consider whether you need additional validation (e.g., no special characters, minimum length). If the contract handles this, current approach is fine.
src/features/autovault/components/vault-detail/vault-collaterals-card.tsx (1)
42-58: LGTM!Consistent handling of
needsSetupstate across vault cards. Gear icon hidden during setup, orange indicator shown.src/features/autovault/components/vault-detail/vault-allocator-card.tsx (1)
34-50: LGTM!Same pattern as vault-collaterals-card. Consistent UI for setup-required state.
src/hooks/useVaultPage.ts (3)
69-89: LGTM!Well-structured initialization checks with clear comments explaining each state. The check at line 88 correctly identifies complete initialization by verifying adapter cap presence.
142-146: Ownership now derived from contract.Good change. Using contract owner instead of API data handles uninitialized vaults correctly since the API returns null for those.
45-45:owneris properly exported from useVaultV2.The hook exports
owner: vaultOwner(line 577), which derives from the smart contract's owner function. The destructuring in useVaultPage.ts is correct.src/features/autovault/components/vault-detail/vault-market-allocations.tsx (1)
67-77: LGTM!Clear conditional messaging for empty state. Helps users understand next steps based on vault initialization status.
src/features/autovault/vault-list-view.tsx (1)
14-50: LGTM!Clean skeleton and benefit card components. Good loading UX.
src/graphql/morpho-api-queries.ts (1)
538-574: Query signature updated correctly - consumer already aligned.The only consumer in
src/data-sources/morpho-api/v2-vaults.tscorrectly passes bothaddressandchainIdvariables matching the new query signature.src/data-sources/morpho-api/v2-vaults.ts (1)
107-119: LGTM - clean early exit and clear documentation.Good guard clause and updated JSDoc explaining the per-address limitation.
src/hooks/useVaultV2.ts (4)
22-31: LGTM - owner read added correctly.Properly guarded with
enabled: Boolean(vaultAddress).
136-160: Metadata setting before timelock operations looks correct.Setting name/symbol before the timelocked operations is intentional - these are non-timelocked calls.
565-577: LGTM - vaultOwner derivation is clean.Fallback to
zeroAddressis reasonable for uninitialized state.
526-533: ERC4626 withdraw parameter mapping is correct.The third parameter
_accountcorrectly maps to the share owner per ERC4626 standard, even though vaultv2 names itonBehalf. The parameter order and semantics are correct.src/features/autovault/components/deployment/deployment-modal.tsx (3)
41-71: LGTM - clean waiting state UI.Good feedback during indexing wait period.
73-124: LGTM - success phase handles both outcomes.Correctly differentiates between having a vault address (navigate) vs not (close).
163-167: Default chain fallback to Base is reasonable.When no token is selected, defaulting to Base is fine since the button is disabled anyway.
src/features/autovault/vault-view.tsx (4)
26-69: LGTM - skeleton matches layout structure.Grid layout mirrors
VaultSummaryMetrics4-column layout.
165-175: Early loading return is cleaner than conditional rendering.Using
vault.isLoadingto show skeleton provides better UX than partial renders.
211-230: Tooltip wrapping the Button requires<span>workaround.This is a known pattern for Radix tooltips on disabled buttons. Looks correct.
256-274: LGTM - condition updated toneedsInitialization.Banner text and logic aligned with new flow.
src/features/autovault/components/deployment/token-selection.tsx (2)
13-22: LGTM - simplified type after removing vault tracking.
44-94: LGTM - clean token aggregation logic.Dependencies list is correct after removing existingVaults.
src/features/autovault/components/deployment/deployment-context.tsx (2)
125-144: LGTM - deployment flow with pre-count tracking.Counting vaults before deployment to detect the new one is a solid approach.
152-167: LGTM - cleanup on reset.Properly clears polling timers and all state.
src/features/autovault/components/deployment/deployment-context.tsx
Outdated
Show resolved
Hide resolved
src/features/autovault/components/deployment/deployment-context.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/history/components/history-table.tsx (1)
229-248: MissingpageSizein useEffect dependency array.
pageSizeis used in the effect but not in deps. Changing page size won't trigger a refetch.void loadTransactions(); - }, [account, currentPage, fetchTransactions, marketIdFilter]); + }, [account, currentPage, pageSize, fetchTransactions, marketIdFilter]);
🧹 Nitpick comments (6)
src/features/autovault/components/vault-detail/total-supply-card.tsx (1)
95-116: Loading state works but consider layout stability and accessibility.The skeleton loading pattern is clean, but the fixed width (
w-32) may not match the actual content width, potentially causing layout shift when data loads. Consider using a more flexible width or multiple skeleton elements to better approximate the final layout.Additionally, the loading state has no screen reader announcement. Adding
aria-live="polite"or a visually-hidden "Loading..." text would improve accessibility.Optional improvements for layout and a11y
- <div className="bg-hovered h-6 w-32 rounded animate-pulse" /> + <div className="bg-hovered h-6 w-48 rounded animate-pulse" aria-label="Loading assets" />Or for better layout approximation:
- <div className="bg-hovered h-6 w-32 rounded animate-pulse" /> + <div className="flex items-center gap-2"> + <div className="bg-hovered h-6 w-24 rounded animate-pulse" /> + <div className="bg-hovered h-5 w-5 rounded-full animate-pulse" /> + <span className="sr-only">Loading assets</span> + </div>src/features/autovault/components/vault-detail/vault-collaterals-card.tsx (1)
80-116: Tooltip for remaining collaterals shows only icons.The remaining tokens tooltip only renders
TokenIconwithout the symbol text. Unlike the allocator card that showsagent.name, this only shows icons. Consider adding token symbols for better UX.Proposed fix
<div key={tokenAddress} className="flex items-center gap-2" > <TokenIcon address={tokenAddress} chainId={chainId} width={16} height={16} + disableTooltip={true} /> + {/* Consider adding token symbol here if available */} </div>src/features/history/components/transaction-history-preview.tsx (1)
23-44: DuplicateformatTimeAgofunction.This exact function exists in
history-table.tsx(lines 52-73). Extract to a shared utility.Suggested location
// src/utils/time.ts export const formatTimeAgo = (timestamp: number): string => { // ... implementation };src/features/autovault/vault-view.tsx (1)
169-190: Settings button missing<span>wrapper.The Settings tooltip button isn't wrapped in a span like the Refresh button. If the button ever becomes disabled, the tooltip won't work.
<Tooltip content={ <TooltipContent title="Settings" detail="Configure vault settings" /> } > + <span> <Button variant="ghost" size="sm" className="text-secondary min-w-0 px-2" onClick={() => { setSettingsTab('general'); setShowSettings(true); }} > <GearIcon className="h-3 w-3" /> </Button> + </span> </Tooltip>src/features/history/components/history-table.tsx (2)
52-73: DuplicateformatTimeAgo- same as transaction-history-preview.tsx.Extract to shared utility.
808-882: Significant code duplication between deposits and withdrawals rendering.These two blocks are nearly identical except for badge color and sign. Consider extracting a shared renderer.
Example extraction
const renderGroupedDepositWithdrawal = ( group: GroupedTransaction, type: 'deposits' | 'withdrawals' ) => { const isDeposit = type === 'deposits'; const badgeColor = isDeposit ? 'text-green-500' : 'text-red-500'; const sign = isDeposit ? '+' : '-'; const label = isDeposit ? 'Deposits' : 'Withdrawals'; // ... shared rendering logic };Also applies to: 884-958
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src/components/common/table-container-with-header.tsxsrc/features/autovault/components/vault-detail/allocations/allocations/collateral-view.tsxsrc/features/autovault/components/vault-detail/allocations/allocations/market-view.tsxsrc/features/autovault/components/vault-detail/total-supply-card.tsxsrc/features/autovault/components/vault-detail/vault-allocator-card.tsxsrc/features/autovault/components/vault-detail/vault-collaterals-card.tsxsrc/features/autovault/components/vault-detail/vault-market-allocations.tsxsrc/features/autovault/vault-view.tsxsrc/features/history/components/history-table.tsxsrc/features/history/components/rebalance-detail.tsxsrc/features/history/components/transaction-history-preview.tsxsrc/features/history/history-view.tsxsrc/features/home/home-view.tsxsrc/utils/storageKeys.tssrc/utils/transactionGrouping.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/home/home-view.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/history/components/rebalance-detail.tsxsrc/features/autovault/components/vault-detail/allocations/allocations/market-view.tsxsrc/features/autovault/components/vault-detail/vault-market-allocations.tsx
📚 Learning: 2024-10-23T16:17:02.841Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 77
File: src/graphql/queries.ts:168-193
Timestamp: 2024-10-23T16:17:02.841Z
Learning: In `src/graphql/queries.ts`, handling only `MarketTransferTransactionData` is intentional at this time.
Applied to files:
src/utils/transactionGrouping.ts
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.
Applied to files:
src/features/autovault/vault-view.tsxsrc/features/history/components/history-table.tsx
🧬 Code graph analysis (8)
src/features/history/components/rebalance-detail.tsx (5)
src/utils/transactionGrouping.ts (3)
GroupedTransaction(3-10)getWithdrawals(15-17)getSupplies(22-24)src/utils/types.ts (1)
Market(293-345)src/features/markets/components/market-identity.tsx (1)
MarketIdentity(32-336)src/utils/balance.ts (1)
formatReadable(25-49)src/utils/oracle.ts (1)
getTruncatedAssetName(478-480)
src/features/autovault/components/vault-detail/allocations/allocations/market-view.tsx (4)
src/utils/vaultAllocation.ts (1)
calculateAllocationPercent(61-65)src/utils/rateMath.ts (1)
convertApyToApr(15-29)src/utils/balance.ts (2)
formatReadable(25-49)formatBalance(21-23)src/features/positions/components/allocation-cell.tsx (1)
AllocationCell(16-76)
src/features/autovault/components/vault-detail/total-supply-card.tsx (3)
src/components/ui/card.tsx (2)
CardHeader(58-58)CardBody(58-58)src/components/shared/token-icon.tsx (1)
TokenIcon(23-95)src/components/ui/tooltip.tsx (1)
Tooltip(52-52)
src/features/autovault/components/vault-detail/allocations/allocations/collateral-view.tsx (3)
src/utils/vaultAllocation.ts (1)
calculateAllocationPercent(61-65)src/utils/balance.ts (1)
formatBalance(21-23)src/features/positions/components/allocation-cell.tsx (1)
AllocationCell(16-76)
src/features/autovault/components/vault-detail/vault-allocator-card.tsx (3)
src/utils/monarch-agent.ts (1)
findAgent(33-35)src/components/shared/agent-icon.tsx (1)
AgentIcon(14-93)src/components/shared/tooltip-content.tsx (1)
TooltipContent(16-71)
src/utils/transactionGrouping.ts (1)
src/utils/types.ts (1)
UserTransaction(37-49)
src/features/autovault/vault-view.tsx (4)
src/components/shared/tooltip-content.tsx (1)
TooltipContent(16-71)src/features/autovault/components/vault-detail/vault-allocator-card.tsx (1)
VaultAllocatorCard(20-138)src/features/autovault/components/vault-detail/vault-collaterals-card.tsx (1)
VaultCollateralsCard(20-127)src/features/history/components/transaction-history-preview.tsx (1)
TransactionHistoryPreview(46-266)
src/features/autovault/components/vault-detail/vault-collaterals-card.tsx (4)
src/components/ui/card.tsx (2)
Card(58-58)CardHeader(58-58)src/components/shared/token-icon.tsx (1)
TokenIcon(23-95)src/components/ui/tooltip.tsx (2)
Tooltip(52-52)TooltipContent(52-52)src/components/shared/tooltip-content.tsx (1)
TooltipContent(16-71)
🔇 Additional comments (28)
src/features/autovault/components/vault-detail/total-supply-card.tsx (3)
4-4: Icon import updated for UI refresh.The switch to
GoPlusCirclealigns with the broader iconography update across the PR.
20-20: Loading prop properly integrated.The optional
isLoadingprop with a default value follows best practices and integrates cleanly with the component signature.Also applies to: 33-33
87-87: Button styling updated for new icon.The className adjustment and icon swap work together cleanly. The deposit button maintains its functionality with refreshed visuals.
Also applies to: 90-90
src/utils/transactionGrouping.ts (3)
1-10: Type and imports look good.Clean type definition for
GroupedTransaction. The optional fields formetaActionTypeandamountappropriately reflect that they're only set for meta-actions.
29-37: Rebalance amount logic is sound.Using the minimum of supplies vs withdrawals correctly captures the "rebalanced" portion. The rest would be net deposits or withdrawals.
45-103: Grouping logic is correct, minor ordering note.The grouping and classification logic is well-structured. One consideration:
txs[0].timestampat line 91 assumes transactions within a group have consistent timestamps. If they differ (e.g., different block times in edge cases), the timestamp would be arbitrary. This is likely fine since same-hash transactions should have the same block timestamp.src/features/history/history-view.tsx (2)
3-11: Clean query param handling.Using
useSearchParamsis the right approach for client-side query param access in Next.js.
20-24: Prop drilling looks fine.The
isVaultAdapterprop is passed through correctly. No issues here.src/utils/storageKeys.ts (1)
25-27: New keys follow existing conventions.Consistent
monarch_prefix and naming pattern.src/features/autovault/components/vault-detail/allocations/allocations/collateral-view.tsx (2)
17-23: Sorting logic is correct.Descending sort by allocation amount. Could use
Number(b.allocation - a.allocation)for brevity, but explicit comparisons are readable.
34-61: AllocationCell integration looks correct.Props match the component signature:
amount(number fromformatBalance),symbol, andpercentage.src/features/autovault/components/vault-detail/vault-collaterals-card.tsx (1)
54-63: Setup required state is clear.Orange indicator with descriptive text. Consistent with the allocator card pattern.
src/components/common/table-container-with-header.tsx (1)
44-89: New variant follows existing patterns.Good JSDoc documentation and consistent styling with
TableContainerWithHeader. The description support is cleanly implemented.src/features/autovault/components/vault-detail/vault-allocator-card.tsx (2)
65-117: Preview with tooltip pattern is well implemented.Consistent with the collaterals card, and this one correctly shows agent names in the tooltip. Clean implementation.
31-42: No issue here—filtering is intentional design.The component only displays agents found in
v2AgentsBase(currently one known agent). This is by design: the system's initialization and settings modals restrict allocators to known agents anyway, since unknown agents lack required metadata (name, icon, description). The filtering aligns with the overall architecture constraint that allocators must come from the hardcoded known list.src/features/history/components/rebalance-detail.tsx (2)
33-60: Row-level null return is fine.Gracefully skipping rows when market data is missing prevents crashes. The
keyusing both hash and idx handles potential duplicates.
64-93: Supplies rendering mirrors withdrawals.Same pattern, consistent styling. The green/red color coding is clear.
src/features/history/components/transaction-history-preview.tsx (1)
89-134: LGTM - clean loading and empty states.The skeleton rows and empty state handling are well structured.
src/features/autovault/components/vault-detail/allocations/allocations/market-view.tsx (2)
43-51: LGTM - clean allocation calculation.The refactor consolidates allocation display into
AllocationCellnicely. Data flow is clear:allocation(bigint) →allocatedAmount(number) andpercentage(number) →AllocationCell.
31-92: Table structure is consistent with the design pattern.Headers and cells align properly. The sorting by allocation amount (descending) is a good UX choice.
src/features/autovault/components/vault-detail/vault-market-allocations.tsx (3)
61-79: LGTM - improved loading skeleton.The skeleton UI is much better than a spinner. Shows expected structure while loading.
81-91: LGTM - context-aware empty state.The conditional message based on
needsInitializationguides users appropriately.
93-108: LGTM - clean toggle implementation.The view mode switch with icon is straightforward.
src/features/autovault/vault-view.tsx (3)
119-135: LGTM - error state handling.Clean fallback UI when vault data fails to load. The back link provides a clear escape path.
148-168: Tooltip wrapper requires<span>for disabled button.Good catch on wrapping the disabled button in a
<span>. Tooltips don't work on disabled elements directly.
326-334: LGTM - TransactionHistoryPreview integration.Correctly gated by
vault.adapterexistence. Props are properly passed.src/features/history/components/history-table.tsx (2)
613-625: Good UX - warning about grouped view pagination.Helpful to inform users about the limitation upfront.
980-1061: LGTM - settings modal implementation.Clean modal with grouped view toggle and page size input. Persists to localStorage.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (1)
131-139: Unused prop:isInitializing.The prop is destructured but never used in the component. Remove it or use it to show a loading state.
Proposed fix
function FinalizeSetupStep({ adapter, registryAddress, - isInitializing, }: { adapter: Address; registryAddress: Address; - isInitializing: boolean; }) {And at line 461:
<FinalizeSetupStep adapter={marketAdapter} registryAddress={registryAddress} - isInitializing={isInitializing} />
♻️ Duplicate comments (2)
src/features/history/components/transaction-history-preview.tsx (2)
59-78: Missing error handling in async effect.The
loadTransactionscall lacks try/catch. If the fetch fails, the component stays in loading state indefinitely andisInitializednever gets set.Suggested fix
useEffect(() => { const loadTransactions = async () => { if (!account || !fetchTransactions || allMarkets.length === 0) return; + try { const result = await fetchTransactions({ userAddress: [account], first: limit, skip: 0, chainIds: chainId ? [chainId] : undefined, }); if (result) { const grouped = groupTransactionsByHash(result.items); setHistory(grouped); } + } catch (error) { + console.error('Failed to fetch transactions:', error); + } setIsInitialized(true); }; void loadTransactions(); }, [account, chainId, limit, fetchTransactions, allMarkets.length]);
143-144: Fallback chainId of 1 may produce wrong explorer links.If market isn't found and
chainIdprop is undefined, defaulting to mainnet will generate incorrect block explorer URLs.
🧹 Nitpick comments (8)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (1)
189-191: Move constants before their usage.
MAX_NAME_LENGTHandMAX_SYMBOL_LENGTHare used inMetadataStep(lines 105, 119) but defined here. Moving them near line 26 improves readability.src/data-sources/morpho-api/v2-vaults.ts (2)
122-146: N+1 query pattern may hit rate limits with many vaults.Each vault triggers a separate API call. For users with many vaults, this could be slow or hit rate limits.
If the API supports batching, consider adding it. Otherwise, this is fine for now but worth monitoring.
131-134: Double error logging.
morphoGraphqlFetcheralready logs and throws on GraphQL errors. This check logs again but doesn't throw - the error is silently swallowed. Consider removing the redundant check or unifying error handling.Suggested fix
const response = await morphoGraphqlFetcher<VaultV2ApiResponse>(vaultV2Query, variables); - if (response.errors && response.errors.length > 0) { - console.error('GraphQL errors:', response.errors); - return null; - } - const vault = response.data?.vaultV2ByAddress;src/utils/vault-indexing.ts (1)
48-48: Type assertion without validation.
JSON.parse(stored) as IndexingVaulttrusts localStorage content. If corrupted, this could cause runtime issues.Optional: add basic shape validation.
Suggested fix
const data = JSON.parse(stored) as IndexingVault; + if (typeof data.address !== 'string' || typeof data.chainId !== 'number' || typeof data.startTime !== 'number') { + localStorage.removeItem(key); + return null; + } const elapsed = Date.now() - data.startTime;src/features/autovault/vault-list-view.tsx (2)
68-91: No cancellation on effect cleanup - possible stale state update.If
addressorisConnectedchanges whilefetchVaultsis in flight, the old promise still runs and updates state. Consider using an abort flag orAbortController.Suggested fix
useEffect(() => { if (!address || !isConnected) { setVaultAddresses([]); setFetchError(null); return; } + let cancelled = false; + const fetchVaults = async () => { setVaultsLoading(true); setFetchError(null); try { const addresses = await fetchUserVaultV2AddressesAllNetworks(address); - setVaultAddresses(addresses); + if (!cancelled) setVaultAddresses(addresses); } catch (_error) { - setFetchError('Unable to load vaults. Please try again.'); + if (!cancelled) setFetchError('Unable to load vaults. Please try again.'); } finally { - setVaultsLoading(false); + if (!cancelled) setVaultsLoading(false); } }; void fetchVaults(); + + return () => { + cancelled = true; + }; }, [address, isConnected]);
93-102: Duplicate fetch logic.
handleRetryFetchduplicates the fetch logic from the effect. Consider extracting to a shared function or just triggering a re-fetch via state.src/features/autovault/components/deployment/deployment-context.tsx (2)
96-97: Unsafe type cast withas any.The cast bypasses TypeScript's type checking. Consider typing the event args properly.
Suggested fix
- const vaultAddress = (decoded.args as any).newVaultV2 as Address; + const vaultAddress = (decoded.args as { newVaultV2: Address }).newVaultV2;Or define a proper type for the CreateVaultV2 event args based on your ABI.
109-111: Silent failure on error.User gets no feedback when deployment fails - just returns to selection phase. Consider showing an error toast.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
src/data-sources/morpho-api/fetchers.tssrc/data-sources/morpho-api/v2-vaults.tssrc/data-sources/subgraph/v2-vaults.tssrc/features/autovault/components/deployment/deployment-context.tsxsrc/features/autovault/components/deployment/deployment-modal.tsxsrc/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsxsrc/features/autovault/components/vault-detail/vault-market-allocations.tsxsrc/features/autovault/vault-list-view.tsxsrc/features/autovault/vault-view.tsxsrc/features/history/components/transaction-history-preview.tsxsrc/graphql/morpho-v2-subgraph-queries.tssrc/hooks/useCreateVault.tssrc/hooks/useVaultIndexing.tssrc/hooks/useVaultPage.tssrc/hooks/useVaultV2.tssrc/utils/vault-indexing.tssrc/utils/vault-storage.ts
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2025-12-09T10:06:39.848Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:39.848Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. In your code under src/hooks, use: const { address, chainId, isConnected } = useConnection() from 'wagmi' to access the connected wallet information.
Applied to files:
src/hooks/useVaultPage.tssrc/hooks/useCreateVault.tssrc/hooks/useVaultIndexing.tssrc/hooks/useVaultV2.ts
📚 Learning: 2024-10-12T09:23:16.495Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/vault-detail/vault-market-allocations.tsx
📚 Learning: 2024-12-17T12:39:21.949Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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/data-sources/subgraph/v2-vaults.ts
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.
Applied to files:
src/features/autovault/vault-list-view.tsxsrc/features/autovault/components/deployment/deployment-modal.tsxsrc/features/autovault/vault-view.tsx
📚 Learning: 2024-12-17T10:51:07.277Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
📚 Learning: 2024-10-23T16:17:02.841Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 77
File: src/graphql/queries.ts:168-193
Timestamp: 2024-10-23T16:17:02.841Z
Learning: In `src/graphql/queries.ts`, handling only `MarketTransferTransactionData` is intentional at this time.
Applied to files:
src/features/history/components/transaction-history-preview.tsx
📚 Learning: 2024-12-16T02:01:51.219Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/deployment/deployment-context.tsx
📚 Learning: 2025-12-09T10:06:43.810Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:43.810Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. Usage: const { address, chainId, isConnected } = useConnection() from 'wagmi'.
Applied to files:
src/features/autovault/components/deployment/deployment-context.tsx
🧬 Code graph analysis (9)
src/features/autovault/components/vault-detail/vault-market-allocations.tsx (1)
src/components/common/table-container-with-header.tsx (1)
TableContainerWithDescription(70-89)
src/data-sources/morpho-api/v2-vaults.ts (2)
src/data-sources/morpho-api/fetchers.ts (1)
morphoGraphqlFetcher(4-29)src/graphql/morpho-api-queries.ts (1)
vaultV2Query(538-574)
src/hooks/useVaultIndexing.ts (2)
src/hooks/useStyledToast.tsx (1)
useStyledToast(6-38)src/utils/vault-indexing.ts (2)
getIndexingVault(41-63)stopVaultIndexing(68-75)
src/features/autovault/vault-list-view.tsx (3)
src/data-sources/subgraph/v2-vaults.ts (1)
fetchUserVaultV2AddressesAllNetworks(80-89)src/utils/vault-storage.ts (1)
getDeployedVaults(52-65)src/components/ui/button.tsx (1)
Button(107-107)
src/features/autovault/components/deployment/deployment-modal.tsx (3)
src/utils/networks.ts (2)
ALL_SUPPORTED_NETWORKS(38-46)isAgentAvailable(203-208)src/features/autovault/components/deployment/deployment-context.tsx (1)
useDeployment(156-162)src/components/ui/button.tsx (1)
Button(107-107)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (2)
src/hooks/useStyledToast.tsx (1)
useStyledToast(6-38)src/utils/vault-indexing.ts (1)
startVaultIndexing(22-34)
src/hooks/useVaultV2.ts (1)
src/abis/vaultv2.ts (1)
vaultv2Abi(3-3)
src/features/history/components/transaction-history-preview.tsx (6)
src/utils/transactionGrouping.ts (1)
groupTransactionsByHash(45-103)src/components/common/table-container-with-header.tsx (1)
TableContainerWithDescription(70-89)src/components/shared/transaction-identity.tsx (1)
TransactionIdentity(19-32)src/utils/types.ts (1)
Market(293-345)src/utils/balance.ts (1)
formatReadable(25-49)src/utils/oracle.ts (1)
getTruncatedAssetName(478-480)
src/features/autovault/components/deployment/deployment-context.tsx (1)
src/utils/vault-storage.ts (1)
addDeployedVault(22-47)
🔇 Additional comments (39)
src/data-sources/subgraph/v2-vaults.ts (3)
42-42: LGTM - reduces runtime noise.Replacing the log with a comment is appropriate for this non-error condition.
62-62: LGTM - consistent with line 42.Removing the log for the no-vaults case keeps logs cleaner.
67-70: LGTM - cleaner direct return.Removing the intermediate variable and log simplifies the code without changing behavior.
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (9)
28-47: LGTM!Clean step indicator implementation.
49-81: LGTM!Status messaging covers the relevant states well.
163-187: LGTM!Agent selection logic is straightforward.
240-250: LGTM!Error handling deferred to hook is fine;
statusVisiblestate drives UI feedback.
252-290: LGTM!Validation, initialization, and indexing flow is well-structured.
292-306: LGTM!State and interval cleanup on close is thorough.
352-423: LGTM!CTA logic per step is clear with proper disabled states.
425-477: LGTM!Modal structure is clean. Step rendering and footer layout look good.
308-328:refetchMarketAdapteris already wrapped inuseCallback.The parent component passes
handleRefetchAdapter(lines 104-106) which is properly memoized withuseCallback, so the polling interval won't restart unnecessarily on parent re-renders.src/graphql/morpho-v2-subgraph-queries.ts (1)
4-17: LGTM!Query ordering by
createdAtBlockNumber descensures newest vaults first. Added timestamp fields are useful.src/hooks/useCreateVault.ts (1)
46-93: LGTM!Return type change to
Promise<string | undefined>allows callers to track the tx hash. Error handling with broader rejection check is good.src/features/history/components/transaction-history-preview.tsx (1)
24-45: LGTM!
formatTimeAgohandles all time ranges well.src/data-sources/morpho-api/fetchers.ts (1)
8-13: LGTM!
cache: 'no-store'ensures fresh data. Appropriate for vault state that changes frequently.src/hooks/useVaultV2.ts (4)
22-31: LGTM!Reading
ownerdirectly from contract is the right approach for uninitialized vaults where API data is unavailable.
136-160: LGTM!Optional metadata setting during initialization improves UX by reducing transaction count. The trim() calls prevent empty string submissions.
565-568: LGTM!
vaultOwnermemoization withzeroAddressfallback is clean.
526-533: No changes needed. The withdraw function signature matches the vault ABI: the third parameter (onBehalfin the ABI) correctly represents the share owner and is being passed as_accountby callers. ERC4626 compliance is maintained; the parameter name differs (onBehalfvs standardowner) but the semantics and position are correct.Likely an incorrect or invalid review comment.
src/hooks/useVaultPage.ts (3)
60-84: LGTM!Clear state machine with good documentation. The initialization check correctly handles the loading/adapter/API data progression.
137-141: LGTM!Using
contractOwnerfor ownership check is correct since API returns null for uninitialized vaults.
173-174: LGTM!Including
allocationsLoadingin the combined loading state prevents partial renders.src/utils/vault-indexing.ts (1)
1-75: LGTM!Clean localStorage utility with auto-cleanup. Error handling and address normalization are good.
src/hooks/useVaultIndexing.ts (2)
138-138:styledToastin deps may cause effect re-runs.
useStyledToastreturns new callback references on each render unless it memoizes them internally. This could trigger the effect repeatedly. Based on the snippet at lines 5-37 ofuseStyledToast.tsx, the callbacks are memoized withuseCallback, so this should be fine.
140-154: Cleanup effect looks good.Properly clears intervals, dismisses toasts, and resets the detection flag on unmount.
src/features/autovault/vault-list-view.tsx (2)
15-52: Skeleton and BenefitCard components are clean.Simple, well-structured presentational components.
112-134: Merge logic is correct.Properly combines API results with local storage, avoiding duplicates via Set lookup.
src/features/autovault/components/vault-detail/vault-market-allocations.tsx (2)
61-79: Loading state handles both data sources.Good that it waits for both
isLoadingandmarketsLoadingbefore showing content.
100-131: Clean conditional rendering.Empty state messages are clear and context-aware. The
TableContainerWithDescriptionwrapper is well integrated.src/utils/vault-storage.ts (1)
22-47: Storage logic is solid.Proper duplicate checking with case-insensitive address comparison. Silent failure with console warning is appropriate for localStorage operations.
src/features/autovault/components/deployment/deployment-modal.tsx (2)
42-92: Success modal flow is clean.Good separation between "has vault address" (show Start Setup) and fallback (show Close). The conditional messaging at lines 65-68 is clear.
130-140: Button state logic simplified.Disabled condition is straightforward. The default to
SupportedNetworks.Baseis fine as a fallback since the button is disabled without selection anyway.src/features/autovault/vault-view.tsx (4)
81-92: Indexing integration looks correct.
isDataLoadedcomputation properly checks loading, error, and data presence. Hook receives necessary params for polling and refetch.
134-166: Loading skeleton during indexing.Good UX - prevents jarring content shifts while waiting for indexing to complete.
376-384: TransactionHistoryPreview gating.Only shown when vault has adapter, is initialized, and caps are configured. The
emptyMessageis helpful for new vaults.
206-216: Tooltip requires span wrapper around disabled button.Wrapping the
Buttonin a<span>is a common pattern to allow tooltips on disabled elements. Works correctly.src/features/autovault/components/deployment/deployment-context.tsx (2)
58-112: Deployment flow extracts address from receipt.This addresses the past review comment about
.at(-1)ordering - now correctly parses the event from the transaction receipt rather than polling. Clean approach.
114-118: Navigation helper is straightforward.Correct dependency array. Routes to the right path when vault address is available.
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
Outdated
Show resolved
Hide resolved
| const tx = group.transactions[0]; | ||
| const market = allMarkets.find((m) => m.uniqueKey === tx.data.market.uniqueKey) as Market | undefined; | ||
| const sign = tx.type === 'MarketSupply' ? '+' : '-'; | ||
| const side = tx.type === 'MarketSupply' ? 'Supply' : 'Withdraw'; | ||
|
|
||
| if (!market) return null; |
There was a problem hiding this comment.
Silent null return hides rows without explanation.
When market is not found, returning null silently removes the row. Users see fewer transactions than expected with no indication why.
Consider logging or filtering these out before rendering.
🤖 Prompt for AI Agents
In src/features/history/components/transaction-history-preview.tsx around lines
230 to 235, the code currently returns null when a market lookup fails which
silently omits rows; instead, filter out transactions with missing markets
upstream (e.g., before mapping/rendering) or explicitly handle the case by
logging a warning with identifying info (transaction id/type/market key) and
return a clear placeholder UI (or skip consistently) so users/developers can see
missing data; implement one consistent approach: either pre-filter the dataset
to remove invalid transactions or replace the null return with a logged warning
and a small fallback row indicating "Market unavailable".
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (3)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (3)
374-387: Consider trimming input values on change or before validation.Validation checks
.trim().lengthbut doesn't trim the state values, so whitespace is passed tocompleteInitialization. While Line 254's comment indicates backend trimming occurs inuseVaultV2, trimming on input would improve consistency.🔎 Trim on change
<Input size="sm" value={vaultName} - onChange={(event) => onNameChange(event.target.value)} + onChange={(event) => onNameChange(event.target.value.trim())} placeholder="e.g., Automonarch USD"Apply similarly to vaultSymbol input.
389-401: Optional: Clarify that agent selection is required.The button is disabled when no agent is selected, but the step description doesn't explicitly state this is required. Consider adding "(required)" to the description or step title.
188-189: Consider moving constants to the top of the file.
MAX_NAME_LENGTHandMAX_SYMBOL_LENGTHare defined mid-file. Moving them near the other constants (lines 18-24) would improve consistency.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsxsrc/hooks/useVaultIndexing.tsxsrc/utils/vault-storage.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/utils/vault-storage.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2024-12-16T02:01:51.219Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
📚 Learning: 2025-12-09T10:06:43.810Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:43.810Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. Usage: const { address, chainId, isConnected } = useConnection() from 'wagmi'.
Applied to files:
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
📚 Learning: 2024-12-17T10:51:07.277Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
🧬 Code graph analysis (2)
src/hooks/useVaultIndexing.tsx (3)
src/hooks/useStyledToast.tsx (1)
useStyledToast(6-38)src/utils/vault-indexing.ts (2)
getIndexingVault(41-63)stopVaultIndexing(68-75)src/components/ui/styled-toast.tsx (1)
StyledToast(3-10)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (2)
src/components/ui/spinner.tsx (1)
Spinner(22-58)src/utils/vault-indexing.ts (1)
startVaultIndexing(22-34)
🔇 Additional comments (6)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (5)
48-80: LGTM - enhanced deployment status messaging.The updated props and conditional messaging improve UX by clearly indicating adapter detection states.
130-160: LGTM - clean finalization step.Simplified display using shortened addresses is appropriate for the review step.
289-303: LGTM - comprehensive cleanup on modal close.State and interval cleanup is properly implemented, preventing memory leaks and stale state.
99-123: No action needed. The Input component properly supports themaxLengthprop through standard HTML input attributes. The component accepts all React.InputHTMLAttributes (includingmaxLength) and passes them to the native input element, which natively enforces the constraint.Likely an incorrect or invalid review comment.
305-325: No action needed. TherefetchMarketAdapterprop (which ishandleRefetchAdapterin the parent) is already memoized withuseCallback, so the polling interval won't restart unnecessarily on re-renders.src/hooks/useVaultIndexing.tsx (1)
132-143: Verify if indexing state should persist across unmounts.The unmount cleanup doesn't call
stopVaultIndexing(vaultAddress, chainId), leaving the indexing state in localStorage. If this is intentional (to resume indexing after navigation), that's fine. Otherwise, stale state will persist until the timeout (2 minutes).Clarify the intended behavior: should indexing state survive component unmount, or should it be cleaned up immediately?
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/features/home/home-view.tsx (1)
350-350: Text change in commented code has no effect.This line is inside a commented-out section (lines 313-376), so the text change from "No performance fees" to "No hidden fees" doesn't affect the rendered page. Consider removing the change or uncommenting if this section is planned for near-term use.
src/hooks/useVaultPage.ts (1)
85-85: Consider simplifying the null check.The explicit
vaultData !== null && vaultData !== undefinedworks but can be shortened tovaultData != null(loose equality null check covers both null and undefined).🔎 Simplified check
- return vaultData !== null && vaultData !== undefined; + return vaultData != null;
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
src/features/autovault/components/deployment/token-selection.tsxsrc/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsxsrc/features/autovault/vault-list-view.tsxsrc/features/autovault/vault-view.tsxsrc/features/home/home-view.tsxsrc/graphql/morpho-v2-subgraph-queries.tssrc/hooks/useDeployMorphoMarketV1Adapter.tssrc/hooks/useVaultIndexing.tsxsrc/hooks/useVaultPage.tssrc/hooks/useVaultV2.tssrc/utils/monarch-agent.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/graphql/morpho-v2-subgraph-queries.ts
- src/hooks/useVaultIndexing.tsx
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2024-12-16T02:01:51.219Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/home/home-view.tsxsrc/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
📚 Learning: 2025-12-09T10:06:39.848Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 231
File: src/hooks/useDeployMorphoMarketV1Adapter.ts:3-3
Timestamp: 2025-12-09T10:06:39.848Z
Learning: In Wagmi v3, useConnection is the correct hook to obtain the connected wallet address, chainId, and connection status (isConnected). This replaces the useAccount hook from Wagmi v2. In your code under src/hooks, use: const { address, chainId, isConnected } = useConnection() from 'wagmi' to access the connected wallet information.
Applied to files:
src/hooks/useVaultPage.tssrc/hooks/useDeployMorphoMarketV1Adapter.tssrc/hooks/useVaultV2.ts
📚 Learning: 2024-12-17T12:39:21.949Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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/monarch-agent.tssrc/features/autovault/components/deployment/token-selection.tsx
📚 Learning: 2024-11-25T09:39:42.148Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 87
File: app/home/HomePage.tsx:17-39
Timestamp: 2024-11-25T09:39:42.148Z
Learning: In `app/home/HomePage.tsx`, the `useEffect` hook depends on `[showCustomized]` because changing `showCustomized` triggers updates to the yield and risk terms.
Applied to files:
src/features/autovault/vault-view.tsxsrc/features/autovault/vault-list-view.tsx
📚 Learning: 2025-11-13T20:32:48.908Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 183
File: app/positions/components/RebalanceModal.tsx:301-308
Timestamp: 2025-11-13T20:32:48.908Z
Learning: The TokenIcon component in the codebase accepts a `symbol` prop as part of its valid interface, in addition to `address`, `chainId`, `width`, `height`, and other props.
Applied to files:
src/features/autovault/components/deployment/token-selection.tsx
📚 Learning: 2024-12-17T10:51:07.277Z
Learnt from: antoncoding
Repo: antoncoding/monarch PR: 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:
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
🧬 Code graph analysis (4)
src/features/autovault/vault-view.tsx (3)
src/hooks/useVaultIndexing.tsx (1)
useVaultIndexing(20-151)src/components/ui/tooltip.tsx (2)
Tooltip(52-52)TooltipContent(52-52)src/components/shared/tooltip-content.tsx (1)
TooltipContent(16-71)
src/features/autovault/components/deployment/token-selection.tsx (3)
src/features/autovault/components/deployment/deployment-context.tsx (1)
useDeployment(156-162)src/components/providers/TokenProvider.tsx (1)
useTokens(131-137)src/utils/balance.ts (1)
formatReadable(25-49)
src/features/autovault/vault-list-view.tsx (3)
src/data-sources/subgraph/v2-vaults.ts (1)
fetchUserVaultV2AddressesAllNetworks(80-89)src/utils/vault-storage.ts (1)
getDeployedVaults(52-65)src/components/ui/button.tsx (1)
Button(107-107)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (4)
src/utils/morpho.ts (1)
getMorphoAddress(8-27)src/utils/networks.ts (1)
getNetworkConfig(183-185)src/abis/morpho-market-v1-adapter-factory.ts (1)
adapterFactoryAbi(3-3)src/utils/vault-indexing.ts (1)
startVaultIndexing(22-34)
🔇 Additional comments (26)
src/features/home/home-view.tsx (1)
284-295: Auto Vault button is now functional and correctly styled.The Link wrapper properly enables navigation to
/autovault, and the button no longer has misleading disabled styling. Good fix.src/utils/monarch-agent.ts (1)
14-14: This is a metadata-only update with no codebase inconsistencies.The description change from "8 hours" to "4 hours" updates only user-facing text. No conflicting references to the old schedule exist in the codebase, and no hardcoded rebalance intervals are implemented in TypeScript. The actual rebalance logic resides in the on-chain smart contract (address 0x038cC0fFf3aBc20dcd644B1136F42A33df135c52), so matching the agent's behavior requires verifying the contract implementation separately.
src/hooks/useVaultPage.ts (2)
202-245: Summary claimscontractOwneris exposed, but it's missing from the return object.The AI summary states "Exposed contractOwner alias (on-chain owner)" but the return object only exposes the derived
isOwnerboolean (line 218), not the rawcontractOwneraddress. If consuming components need access to the owner address, consider adding it to the return object.
62-201: Initialization flow logic is well-structured.The new
isVaultInitializedandneedsInitializationcomputed states correctly model the vault deployment stages. The ownership derivation properly switched to on-chain data (contractOwner) to handle uninitialized vaults where the API returns null. The loading synchronization (line 176) now correctly waits for all parallel queries.src/hooks/useDeployMorphoMarketV1Adapter.ts (1)
49-63: LGTM!The explicit return type and transaction hash propagation improve caller observability. Early exit handling is clear.
src/hooks/useVaultV2.ts (5)
22-31: LGTM!Owner read via
useReadContractfollows Wagmi v3 patterns correctly.
88-88: Dynamic toast IDs prevent collisions.Including
vaultAddressin toast IDs allows multiple vault operations to show distinct toasts simultaneously.Also applies to: 102-102, 112-112, 123-123, 474-474, 485-485
525-531: Parameter rename aligns with ERC-4626.The
_accountparameter name matches the ERC-4626 standard signature forwithdraw(uint256 assets, address receiver, address owner).
563-575: LGTM!The
vaultOwnermemo safely handles undefined and exposes owner in the hook's return value.
135-262: No action needed. setName and setSymbol are owner-only functions that execute instantly without timelock, so wrapping them insubmit()would be incorrect. The code handles these correctly by encoding them directly.Likely an incorrect or invalid review comment.
src/features/autovault/vault-list-view.tsx (5)
64-66: LGTM!The mounting guard prevents hydration mismatches between server and client.
Also applies to: 150-150, 168-168
68-91: LGTM!Fetch logic handles loading, error states, and empty results cleanly. Errors don't clear existing data, which is good UX.
136-141: LGTM!Navigation to the first vault provides a quick entry point when multiple vaults exist.
148-262: LGTM!UI restructure cleanly handles loading, error, connected/not-connected, and vault ownership states. The hero section and benefits grid provide a clear value proposition.
112-134: The merge logic already uses.toLowerCase()for the dedup key comparison, so it safely handles address casing inconsistencies. Both sources (subgraph and local storage) should return addresses consistently, but the code is protected regardless.src/features/autovault/components/deployment/token-selection.tsx (3)
114-126: LGTM!Sort logic places USDC Base first, then by balance descending, then alphabetically. This provides a predictable and user-friendly ordering.
178-233: LGTM!The "Suggested" badge clearly indicates USDC Base with 0 balance, helping users understand the default choice.
13-15: This address is the official USDC contract on Base.src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (4)
237-285: LGTM!The deploy flow waits for the transaction receipt and decodes the
CreateMorphoMarketV1Adapterevent to extract the adapter address. This ensures the adapter address is captured immediately without waiting for subgraph indexing.
287-325: LGTM!The initialization flow passes name/symbol to
completeInitialization, then starts vault indexing and triggers a refetch. Error handling relies on the hook's toast, which is appropriate.
74-120: LGTM!The
MetadataStepcomponent provides clear input fields with appropriate placeholders and length limits.
180-181: Verify that contract enforces matching length constraints on name and symbol.The UI enforces
MAX_NAME_LENGTH = 64andMAX_SYMBOL_LENGTH = 16via inputmaxLengthattributes, but contract source code is not available in this repository to confirm these match any on-chain constraints. If the contract doesn't enforce the same limits, inputs could succeed on the UI and then fail during transaction execution.src/features/autovault/vault-view.tsx (4)
84-168: LGTM!The
useVaultIndexinghook integration provides a smooth loading experience during indexing, with a skeleton UI preventing layout shifts.
194-243: LGTM!Tooltip-wrapped Refresh and Settings buttons improve discoverability and explain their purpose clearly.
378-386: LGTM!Transaction history is only shown when the vault is fully initialized and caps are configured, which prevents showing an empty history during setup.
429-430: LGTM!The
completeInitializationandisInitializingprops are correctly passed to the initialization modal, enabling the full setup flow.
Summary by CodeRabbit
New Features
Improvements
Removed
✏️ Tip: You can customize this high-level summary in your review settings.