Skip to content

feat: vault v2 agent wip 1#159

Merged
antoncoding merged 9 commits intomasterfrom
feat/agent-vault-v2
Sep 28, 2025
Merged

feat: vault v2 agent wip 1#159
antoncoding merged 9 commits intomasterfrom
feat/agent-vault-v2

Conversation

@antoncoding
Copy link
Owner

@antoncoding antoncoding commented Sep 28, 2025

Summary by CodeRabbit

  • New Features
    • Autovault: listing, deploy flow, vault details page with owner-only settings and deploy modal.
  • Improvements
    • Onboarding & positions: market-selection table, refined distribution controls, BigInt-precise amount input, cross-network balance support.
  • UI/UX
    • Autovault link added to navbar (unauthenticated), simplified success and modal screens, refined token tooltips and visuals.
  • Removals
    • Monarch Agent setup and related UI removed.
  • Performance
    • Balance requests now target supported tokens only.

@vercel
Copy link
Contributor

vercel bot commented Sep 28, 2025

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

Project Deployment Preview Comments Updated (UTC)
monarch Ready Ready Preview Comment Sep 28, 2025 9:50am

@coderabbitai
Copy link

coderabbitai bot commented Sep 28, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Autovault pages & UI
app/autovault/page.tsx, app/autovault/[vaultAddress]/page.tsx, app/autovault/[vaultAddress]/content.tsx, app/autovault/[vaultAddress]/components/VaultSettings.tsx, app/autovault/components/AutovaultContent.tsx, app/autovault/components/VaultListV2.tsx
Adds Autovault pages, vault detail page, VaultSettings component, main Autovault content, and a vault list UI with token/balance rendering.
Autovault deployment flow
app/autovault/components/deployment/DeploymentContext.tsx, app/autovault/components/deployment/DeploymentModal.tsx, app/autovault/components/deployment/TokenSelection.tsx, src/hooks/useCreateVault.ts
Adds deployment context, modal, token+network selector, and useCreateVault hook to build/send createVaultV2 transactions.
Subgraph / data sources / ABI
src/data-sources/subgraph/v2-vaults.ts, src/graphql/morpho-v2-subgraph-queries.ts, src/abis/vaultv2factory.ts, src/hooks/useUserVaultsV2.ts
Adds subgraph query, fetchers for user V2 vaults across networks, VaultV2Factory ABI, and a hook to fetch/enrich V2 vaults with balances.
Networks / config accessors
src/utils/networks.ts
Adds VaultAgentConfig and NetworkConfig types, vault-specific data (e.g., Base v2FactoryAddress/subgraphEndpoint), and accessors: getNetworkConfig, getAgentConfig, isAgentAvailable, isSupportedChain.
Balances API & token utilities
app/api/balances/route.ts, src/hooks/useUserBalances.ts, src/components/providers/TokenProvider.tsx, src/utils/erc20.ts
Balances API now filters Alchemy requests to supported token addresses; useUserBalances accepts optional networkIds and adds useUserBalancesAllNetworks; TokenProvider guards for missing inputs; adds getERC20Balance utility.
Positions & onboarding changes
app/positions/components/PositionsContent.tsx, app/positions/components/PositionsSummaryTable.tsx, src/utils/positions.ts, src/hooks/useUserRebalancerInfo.ts, app/positions/components/onboarding/Modal.tsx, app/positions/components/onboarding/SuccessPage.tsx, app/positions/components/onboarding/AssetSelection.tsx, app/positions/components/onboarding/RiskSelection.tsx, app/positions/components/onboarding/SetupPositions.tsx, app/positions/components/onboarding/OnboardingContext.tsx
Removes Monarch agent/rebalancer UI and props, drops rebalancerInfos usage, switches many onboarding flows to all-network balances, overhauls RiskSelection/SetupPositions UI and inputs, and simplifies onboarding modal APIs and success page.
Navbar link
src/components/layout/header/Navbar.tsx
Adds Autovault navigation link in the unauthenticated (not mounted) branch; keeps mounted link commented.
UI tweaks (minor)
src/components/TokenIcon.tsx, src/components/Input/Input.tsx, src/components/SupplyModalContent.tsx
Refactors TokenIcon tooltip styling, simplifies conditional rendering in Input, and rewrites a ternary grouping in SupplyModalContent; no behavioral changes.
Market components formatting
app/market/[chainId]/[marketid]/components/CampaignBadge.tsx, .../CampaignModal.tsx, .../PositionStats.tsx
ClassName ordering and JSX whitespace/formatting changes only.
Formatting / small edits
scripts/generate-chainlink-data.ts, src/config/dataSources.ts, src/constants/oracle/chainlink-data/*, src/constants/oracle/chainlink-data/index.ts, src/contexts/MarketsContext.tsx, src/utils/external.ts, src/utils/morpho.ts, src/utils/rpc.ts, src/utils/subgraph-urls.ts, src/utils/tokens.ts, src/store/createWagmiConfig.ts, src/utils/monarch-agent.ts
Many whitespace/semicolons/newline/trailing-comma adjustments and one new export (v2AgentsBase); no runtime semantics changes except formatting.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • feat: vault v2 agent wip 1 #159 — Appears to contain overlapping Autovault and balances changes (very likely-code-level overlap).
  • feat: arbitrum #158 — Related changes to the balances endpoint and network handling; directly connected to app/api/balances/route.ts edits.
  • feat: onboarding flow! #84 — Earlier work on the Alchemy balances endpoint; relevant because this PR narrows that request to supported token addresses.

Poem

New vaults arise where subgraphs hum,
A modal opens: pick token, then run.
Chains may shift, transactions fly,
Old agent buttons waved goodbye.
Deploy and refresh — the dashboard sings, vaults multiply.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title “feat: vault v2 agent wip 1” is vague and includes a “wip” marker that suggests it’s a work in progress rather than a clear summary of the primary change. It does not convey the main feature being added, such as the new Vault V2 deployment and UI components, and it fails to provide meaningful context for reviewers scanning pull request history. Please rename the pull request to a concise phrase that clearly describes the core feature, for example “feat: add Vault V2 factory ABI and deployment UI” or “feat: implement Vault V2 agent deployment and settings pages.” This will help teammates understand the main purpose at a glance.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.89% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7814475 and c96e961.

📒 Files selected for processing (4)
  • app/autovault/components/VaultListV2.tsx (1 hunks)
  • app/autovault/components/deployment/TokenSelection.tsx (1 hunks)
  • src/hooks/useUserVaultsV2.ts (1 hunks)
  • src/utils/erc20.ts (1 hunks)

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.

Copy link

@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: 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 lost

The pre-filter removes every position with zero supplyShares, so entries that only carry historical earnings never reach shouldInclude. Previously those market rows still surfaced because we checked getEarningsForPeriod before 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).

require isn’t available in ESM; this will crash when run via tsx. Switch to an import.meta.url check.

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 missing response.ok check.

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 expects string (not string | undefined). This can fail type-checking. Also, keep arbitrum var 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.
useUserBalancesAllNetworks returns entries for every network. Matching only on address will grab the first hit—tokens like WETH live at 0x4200… 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 to BigInt (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 building v2AgentsBase from agents so 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 1 can 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 isAddressEqual avoids 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 generateMetadata and 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 abi export and keep literal types with satisfies Abi for 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 Abi
app/autovault/[vaultAddress]/components/VaultSettings.tsx (1)

5-10: Prop vault is 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 NetworkIcon at src/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 on findToken (and trim unused state).

useMemo uses findToken but it’s not in deps; allTokens isn’t used. Depend on findToken and drop allTokens.

-  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 SupportedNetworks then checking truthiness adds no value. Use isSupportedChain to 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 and aria-label on 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.values on a numeric enum includes string keys; safer to check against networks.

-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 fetchAllBalances is called while loading is 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.

isAgentAvailable or networks won’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

📥 Commits

Reviewing files that changed from the base of the PR and between ba6f67e and 7814475.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is 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.tsx
  • app/positions/components/onboarding/SuccessPage.tsx
  • app/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.tsx
  • app/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.ts
  • src/hooks/useLiquidations.ts
  • src/hooks/useUserBalances.ts
  • app/positions/components/onboarding/AssetSelection.tsx
  • app/autovault/components/deployment/TokenSelection.tsx
  • src/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 solid

Logic is unchanged and reads cleaner.


50-52: Initial view mode selection looks right

State still defaults to user view only when a position exists.


207-209: Whitespace tweak keeps APY display intact

No 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 classNames keeps the wrapper neutral and lets TooltipContent own the visuals. No issues spotted.

app/autovault/page.tsx (1)

5-10: Metadata setup LGTM.

Assuming generateMetadata handles empty pathname for /autovault. If not, pass it explicitly.

src/graphql/morpho-v2-subgraph-queries.ts (1)

5-13: Fix GraphQL field name and variable type

  • Rename createVaultV2S to match the schema’s collection name (e.g. createVaultV2s).
  • Update the $owner variable from String! to Bytes! if the schema defines owner: 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.id and token address is clear and safe.

Based on learnings


143-155: Verify APY units and balance type.

  • Confirm market.state.supplyApy is a fraction (0.05) before multiplying by 100; otherwise you’ll show 100x.
  • Ensure balance.balance is 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.

onPress matches the shared Button component.

@antoncoding antoncoding merged commit 33c2865 into master Sep 28, 2025
2 of 4 checks passed
@antoncoding antoncoding deleted the feat/agent-vault-v2 branch September 28, 2025 09:44
@coderabbitai coderabbitai bot mentioned this pull request Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant