Skip to content

fix: vault deployment and caps#324

Merged
antoncoding merged 6 commits intomasterfrom
fix/vault-deployment
Jan 26, 2026
Merged

fix: vault deployment and caps#324
antoncoding merged 6 commits intomasterfrom
fix/vault-deployment

Conversation

@antoncoding
Copy link
Copy Markdown
Owner

@antoncoding antoncoding commented Jan 26, 2026

  • Simplify cap setting logic

Summary by CodeRabbit

  • New Features

    • Allocator cards can show an optional image.
    • Market cap rows support removal/undo and show "New" or "Removed" states.
  • UI/UX Updates

    • "Agent" label changed to "Allocator".
    • Deposit action label standardized to "Deposit".
    • Minor layout and spacing refinements; onboarding/init messaging clarified.
  • Improvements

    • Vault indexing now uses a centralized reactive store with timed refetching, toasts, and timeout handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jan 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
monarch Ready Ready Preview, Comment Jan 26, 2026 4:14am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 26, 2026

Warning

Rate limit exceeded

@antoncoding has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 36 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Migrates vault indexing from a localStorage utility to a central Zustand store, updates useVaultIndexing and VaultInitializationModal to the new store API, adds optional allocator images and UI tweaks, and refactors market-cap editing/removal behavior and related tables.

Changes

Cohort / File(s) Summary
Vault indexing store & API
src/stores/vault-indexing-store.ts, src/hooks/useVaultIndexing.tsx, src/utils/vault-indexing.ts (deleted)
Adds a new Zustand store (useVaultIndexingStore, INDEXING_TIMEOUT_MS), removes the localStorage utility, changes hook API (isDataLoadedhasPostInitData), implements store-driven indexing lifecycle, toasts, and 10s refetch interval/10min timeout.
Vault initialization modal
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx
Replaces localStorage-indexing calls with startIndexing(...), adjusts step labels to "Choose an Allocator", passes image to allocator cards, and tweaks modal padding and reset logic.
Allocator card component
src/components/shared/allocator-card.tsx
Adds optional image?: string prop and conditional Image render, removes AccountIdentity/chain-dependent logic, replaces header with compact avatar/name/sliced address, and adjusts spacing/selected indicator sizing.
Market caps editing logic
src/features/autovault/components/vault-detail/settings/EditCaps.tsx
Drops CollateralCapInfo/state, introduces removedMarketIds and read-only collateralCapMap, reworks save flow to derive collateral caps from active markets, supports remove/undo semantics, and updates hasChanges/reset behavior.
Market caps table UI
src/features/autovault/components/vault-detail/settings/MarketCapsTable.tsx
Adds per-row isRemoved/collateralCapPercent, onRemove/onUndoRemove callbacks, renders Removed/Editable/Read-only modes, shows collateral-constraining indicator and "New" badge, and tightens validation/formatting.
Vault view & refetching
src/features/autovault/vault-view.tsx
Stabilizes refetch references, replaces data-loaded sentinel with hasPostInitData, updates indexing trigger to use post-init condition, and updates onboarding text.
Deposit modal
src/modals/vault/vault-deposit-modal.tsx
Simplifies ExecuteTransactionButton label to a static "Deposit" (removes conditional label logic).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Modal as "VaultInitializationModal"
participant Hook as "useVaultIndexing"
participant Store as "vault-indexing-store\n(useVaultIndexingStore)"
participant Queries as "Queries / Refetch"
participant Toast as "Toast System"

Modal->>Hook: call useVaultIndexing({ vaultAddress, chainId, hasPostInitData, refetch })
Hook->>Store: subscribe to indexingVault
Modal->>Store: startIndexing(vaultAddress, chainId)
Store-->>Hook: indexingVault updated
Hook->>Toast: show persistent "Indexing started" toast
Hook->>Queries: periodic refetch() every 10s while indexing
Queries-->>Hook: refetch results
alt hasPostInitData becomes true
Hook->>Store: stopIndexing()
Hook->>Toast: dismiss persistent toast and show success
else timeout reached (10 min)
Hook->>Store: stopIndexing()
Hook->>Toast: dismiss persistent toast and show timeout/info
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • antoncoding/monarch#259 — similar migration to a store-based vault indexing flow and related hook updates.
  • antoncoding/monarch#162 — overlapping changes to AllocatorCard (image prop and header rendering adjustments).
  • antoncoding/monarch#319 — related edits to EditCaps.tsx and market/cap save/remove behavior.
🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'fix: vault deployment and caps' relates to changes in vault initialization and cap management, but is vague and doesn't capture the core refactoring work (store migration, UI simplification, allocator changes). Consider a more specific title like 'refactor: migrate vault indexing to store and simplify caps' to better reflect the actual scope of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/vault-deployment

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the bug Something isn't working label Jan 26, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/features/autovault/components/vault-detail/settings/EditCaps.tsx`:
- Around line 138-163: The closure bug comes from using wasNewCap after calling
setMarketCaps; instead, determine whether the cap is new or existing by reading
the previous marketCaps inside the same updater and update removedMarketIds from
there. In handleRemoveMarketCap (the function), remove wasNewCap and change
setMarketCaps to a single updater that inspects prev.get(key): if info &&
!info.existingCapId, create a new Map, delete the key and return it; otherwise
(existing on-chain cap) return prev and call setRemovedMarketIds(prev => { const
next = new Set(prev); next.add(key); return next; }) from within the branch so
the removed set is updated synchronously based on the prev state you inspected.

In `@src/hooks/useVaultIndexing.tsx`:
- Around line 17-23: The doc comment for useVaultIndexing incorrectly states a
2-minute timeout while the store uses INDEXING_TIMEOUT_MS set to 10 minutes;
update the documentation/comment block above useVaultIndexing to reflect the
actual timeout (10 minutes) or reference the INDEXING_TIMEOUT_MS constant
directly so they stay in sync, ensuring the description of retry behavior and
timeout matches the INDEXING_TIMEOUT_MS value used by the hook.
🧹 Nitpick comments (4)
src/modals/vault/vault-deposit-modal.tsx (1)

114-123: Static "Deposit" label may mislead users during approval flow.

The button now always shows "Deposit" even when an approval transaction is required first. Users might expect visual feedback about the current step. The internal logic at lines 60-66 still handles both paths correctly.

If this simplification is intentional for UX reasons, consider adding a subtitle or secondary indicator when approval is pending.

src/features/autovault/components/vault-detail/settings/EditCaps.tsx (1)

299-309: Empty relativeCap string with absoluteCap set results in 0% relative cap.

If user clears relativeCap but sets an absoluteCap, newRelativeCapBigInt stays 0n. This might not be intended—typically you'd want at least some relative allocation if absolute is set.

Consider whether this edge case needs validation or if the current behavior is acceptable.

src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (2)

296-299: Unsafe type cast.

as any bypasses type checking. The ABI should provide proper typing.

Suggested fix
-        const adapter = (decoded.args as any).morphoMarketV1Adapter as Address;
+        const adapter = (decoded.args as { morphoMarketV1Adapter: Address }).morphoMarketV1Adapter;

369-374: Implicit undefined comparison.

marketAdapter can be undefined. The comparison undefined !== ZERO_ADDRESS is true, so this works—but an explicit check is clearer.

Optional explicit check
   useEffect(() => {
-    if (marketAdapter !== ZERO_ADDRESS && stepIndex === 0 && deployedAdapter === ZERO_ADDRESS) {
+    if (marketAdapter && marketAdapter !== ZERO_ADDRESS && stepIndex === 0 && deployedAdapter === ZERO_ADDRESS) {
       setStepIndex(1);
     }
   }, [marketAdapter, stepIndex, deployedAdapter]);

Comment thread src/hooks/useVaultIndexing.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/features/autovault/components/vault-detail/settings/EditCaps.tsx`:
- Around line 289-304: The code calls parseUnits with info.relativeCap and
info.absoluteCap which can throw InvalidDecimalNumberError for malformed
strings; before calling parseUnits in the block inside EditCaps (where
newRelativeCapBigInt and newAbsoluteCapBigInt are set), validate the input
strings (e.g. ensure info.relativeCap and info.absoluteCap match a
decimal-number regex like /^\d+(\.\d+)?$/) or wrap each parseUnits(...) call in
a try-catch that handles InvalidDecimalNumberError (e.g. set the cap to 0n or
maxUint128 as appropriate and surface a validation error), referencing
parseUnits, info.relativeCap, info.absoluteCap, newRelativeCapBigInt,
newAbsoluteCapBigInt and maxUint128 to locate the changes.
🧹 Nitpick comments (4)
src/features/autovault/components/vault-detail/modals/vault-initialization-modal.tsx (2)

66-66: Nested ternary is fine here, but consider extracting for clarity.

The logic is straightforward. If this grows, consider a small helper or early return pattern.


239-239: Type assertion before nullish coalescing is slightly awkward.

The cast happens before ??, so you're asserting undefined as Address when array is empty. Works at runtime, but cleaner to move the cast after:

♻️ Optional cleanup
-const [selectedAgent, setSelectedAgent] = useState<Address | null>((v2AgentsBase.at(0)?.address as Address) ?? null);
+const [selectedAgent, setSelectedAgent] = useState<Address | null>(
+  (v2AgentsBase.at(0)?.address ?? null) as Address | null
+);
src/features/autovault/components/vault-detail/settings/EditCaps.tsx (2)

138-157: Nested setState is an anti-pattern.

Calling setRemovedMarketIds inside the setMarketCaps updater can cause unpredictable batching behavior. Move the check outside.

Suggested refactor
 const handleRemoveMarketCap = useCallback((marketId: string) => {
   hasUserEditsRef.current = true;
   const key = marketId.toLowerCase();
+  const info = marketCaps.get(key);
+  
+  if (!info) return;

-  setMarketCaps((prev) => {
-    const info = prev.get(key);
-    if (!info) return prev;
-
-    if (!info.existingCapId) {
-      // Newly added cap — remove from state entirely
-      const next = new Map(prev);
-      next.delete(key);
-      return next;
-    }
-
-    // Existing on-chain cap — mark as removed (will be zeroed on save)
-    setRemovedMarketIds((prevRemoved) => new Set(prevRemoved).add(key));
-    return prev;
-  });
-}, []);
+  if (!info.existingCapId) {
+    // Newly added cap — remove from state entirely
+    setMarketCaps((prev) => {
+      const next = new Map(prev);
+      next.delete(key);
+      return next;
+    });
+  } else {
+    // Existing on-chain cap — mark as removed (will be zeroed on save)
+    setRemovedMarketIds((prev) => new Set(prev).add(key));
+  }
+}, [marketCaps]);

375-375: Memoize existingMarketIds.

This creates a new Set on every render, potentially causing unnecessary child re-renders.

Suggested fix
-const existingMarketIds = new Set(Array.from(marketCaps.keys()).filter((key) => !removedMarketIds.has(key)));
+const existingMarketIds = useMemo(
+  () => new Set(Array.from(marketCaps.keys()).filter((key) => !removedMarketIds.has(key))),
+  [marketCaps, removedMarketIds]
+);

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/hooks/useVaultIndexing.tsx`:
- Around line 64-87: The effect in useVaultIndexing watches only isIndexing so
when startIndexing is called again the old interval keeps using the previous
startTime; update the effect to also depend on the vault start time
(indexingVault?.startTime) or a derived startTime variable so the interval is
reset whenever startTime changes, ensuring the timeout calculation uses the
newest startTime; modify the dependency array for the useEffect that contains
refetch/clearInterval to include indexingVault?.startTime (or startTime) and
ensure the intervalId is cleared on cleanup and restart when startTime updates.

Comment thread src/hooks/useVaultIndexing.tsx
@antoncoding antoncoding merged commit 75c066e into master Jan 26, 2026
4 checks passed
@antoncoding antoncoding deleted the fix/vault-deployment branch January 26, 2026 04:15
@coderabbitai coderabbitai Bot mentioned this pull request Jan 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ui User interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant