Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
461c173
chore: styling detail on onboarding flow
antoncoding Oct 7, 2025
c2c7c2e
chore: setup modal
antoncoding Oct 7, 2025
de43ca6
feat: init function
antoncoding Oct 7, 2025
00a41f0
chore: move folder structure to include chain Id
antoncoding Oct 7, 2025
d8e0041
feat: setting modal
antoncoding Oct 7, 2025
a2985a9
chore: fix lint
antoncoding Oct 7, 2025
929dd3e
chore: layout
antoncoding Oct 8, 2025
f79e759
feat: modal layout
antoncoding Oct 8, 2025
f8bb418
feat: table
antoncoding Oct 9, 2025
33b4b20
chore: stash
antoncoding Oct 12, 2025
906f36c
refactor: allocation tab
antoncoding Oct 16, 2025
cb99a60
refactor: vault cap system
antoncoding Oct 16, 2025
e7e8255
chore: parsing logic
antoncoding Oct 16, 2025
ca87d15
chore: new parsing logic
antoncoding Oct 16, 2025
0abba73
feat: correct decode
antoncoding Oct 16, 2025
9fb2902
feat: new flow
antoncoding Oct 17, 2025
e8fca38
feat: set caps done
antoncoding Oct 17, 2025
949b6c6
feat: deposit
antoncoding Oct 17, 2025
9768822
feat: rename allocation -> cap
antoncoding Oct 20, 2025
9c43219
feat: fix allocations
antoncoding Oct 21, 2025
d69fe24
fix: refetch logics and cleanup adapter
antoncoding Oct 21, 2025
5b389bb
refactor: data hooks
antoncoding Oct 21, 2025
2360f22
feat: unified market id badge
antoncoding Oct 22, 2025
4730888
feat: market identity
antoncoding Oct 22, 2025
97180d1
feat: MarketIdentity and MarketIdBadge
antoncoding Oct 22, 2025
fc5eb3e
fix: details
antoncoding Oct 22, 2025
4585612
chore: feedbacks
antoncoding Oct 22, 2025
5565754
chore: feedback
antoncoding Oct 22, 2025
ce75908
chore: fix chainid usage
antoncoding Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
"WebFetch(domain:www.heroui.com)",
"WebSearch",
"Bash(pnpm generate:chainlink:*)",
"Bash(pnpm lint:check:*)"
"Bash(pnpm lint:check:*)",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate permission entry.

Line 22 duplicates the permission already defined on line 12.

      "Bash(pnpm generate:chainlink:*)",
-     "Bash(pnpm lint:check:*)",
      "Bash(pnpm exec tsc:*)",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"Bash(pnpm lint:check:*)",
"Bash(pnpm generate:chainlink:*)",
"Bash(pnpm exec tsc:*)",
"Bash(pnpm lint:check:*:2)",
"Bash(npx eslint:*)",
"Bash(git rm:*)",
🤖 Prompt for AI Agents
In .claude/settings.local.json around line 22 (line 22 duplicates an entry
present at line 12): remove the duplicate permission string "Bash(pnpm
lint:check:*)" so it only appears once in the permissions array, then verify the
JSON remains valid (adjust surrounding commas if necessary) and scan for any
other duplicated permission entries to avoid redundancy.

"Bash(pnpm exec tsc:*)",
"Bash(npx eslint:*)",
"Bash(git rm:*)"
Comment thread
antoncoding marked this conversation as resolved.
],
"deny": []
}
}
}
40 changes: 40 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Repository Guidelines

## Project Structure & Module Organization
Next.js routes live in `app/`. Shared logic sits in `src/` with UI in `src/components/`, hooks in `src/hooks/`. Keep constants inside `src/constants/`, configuration in `src/config/`, and reusable utilities in `src/utils/`. Static assets stay in `public/`; design primitives reside in `src/fonts/` and `src/imgs/`. Scripts that generate on-chain artifacts live under `scripts/`, and longer form references or RFCs belong in `docs/`.

## Build, Test, and Development Commands
- `pnpm install` — install dependencies; stick with pnpm for lockfile parity.
- `pnpm dev` — start the hot-reloading Next.js dev server.
- `pnpm build` — create a clean production bundle after wiping `.next`.
- `pnpm start` — run the production build locally when validating releases.
- `pnpm check` — run formatting, ESLint, and Stylelint fixers as a bundle.
- `pnpm lint` / `pnpm stylelint` — target React or CSS changes without the full suite.

## Coding Style & Naming Conventions
Run `pnpm format` to apply the Prettier profile (100-char width, 2-space indent, single quotes, trailing commas, Tailwind-aware ordering). ESLint (Airbnb + Next.js) enforces hook safety and import hygiene; Stylelint keeps CSS utilities consistent. Use PascalCase for React components (`VaultBanner.tsx`), camelCase for helpers (`formatApr`), and SCREAMING_SNAKE_CASE for shared constants. Keep Tailwind classlists purposeful and lean; consolidate patterns with `tailwind-merge` helpers when they repeat.

## Styling Discipline
Consult `docs/Styling.md` before touching UI. Always follow the documented design tokens, Tailwind composition patterns, and variant rules—no exceptions. Mirror the examples in that guide for component structure, prop naming, and class ordering so the design system stays coherent. When using the shared `Spinner` component, pass numeric pixel values (e.g. `size={12}`)—it does not accept semantic strings.

## Implementation Mindset
Default to the simplest viable implementation first. Reach for straightforward data flows, avoid premature abstractions, and only layer on complexity when the trivial approach no longer meets requirements.

## Function Organization & Separation of Concerns
Never define utility functions or business logic inside hooks, components, or classes. Extract them into dedicated utility files in `src/utils/`. This principle—often called **Single Responsibility Principle** or **Separation of Concerns**—keeps code testable, reusable, and maintainable. For example:
- ❌ Bad: Defining `readAllocation()` inside `useAllocations.ts`
- ✅ Good: Creating `src/utils/vaultAllocation.ts` with `readAllocation()`, `formatAllocationAmount()`, etc., then importing into the hook

Hooks should orchestrate effects and state; components should render UI; utilities should handle pure logic. Keep each layer focused on its single responsibility.

## Git Ownership
Never run git commits, pushes, or other history-altering commands—leave all git operations to the maintainers.

## Contract Interaction TL;DR
When writing new on-chain hooks, mirror the structure in `src/hooks/useERC20Approval.ts` and `src/hooks/useTransactionWithToast.tsx`: compute chain/address context up front, reuse `useTransactionWithToast` for consistent toast + confirmation handling, and expose a minimal hook surface (`{ action, isLoading }`) with refetch callbacks for follow-up reads.

## Commit & Pull Request Guidelines
Mirror the Conventional Commits style in history (`feat:`, `fix:`, `chore:`), keeping messages imperative and scoped. Sync with `main`, run `pnpm check`, and capture UI evidence (screenshots or short clips) for anything user-facing. Reference the relevant Linear/Jira ticket with closing keywords, call out risk areas, and flag required follow-ups. Tag reviewers who understand the touched protocol surfaces to speed feedback.

## Incident Log
- Autovault settings refactor: we unintentionally spammed the Morpho API because we passed fresh array literals (`defaultAllocatorAddresses`) into `useVaultV2Data`. That array was part of the hook’s memoised fetch dependencies, so every render produced a new reference, rebuilt the `useCallback`, and re-triggered the fetch effect. **Guardrail:** before handing arrays or objects to hooks that fire network requests, memoize the props (or pass a stable key) so React’s dependency checks only change when the underlying data truly changes.
1 change: 1 addition & 0 deletions app/api/balances/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export async function GET(req: NextRequest) {
});

if (!balancesResponse.ok) {
console.error(`Failed to fetch balances: ${balancesResponse.status} ${balancesResponse.statusText}`);
throw new Error(`HTTP error! status: ${balancesResponse.status}`);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import React from 'react';
import { Cross1Icon } from '@radix-ui/react-icons';
import { Address } from 'viem';
import { useAccount } from 'wagmi';
import { Button } from '@/components/common';
import Input from '@/components/Input/Input';
import AccountConnect from '@/components/layout/header/AccountConnect';
import { TokenIcon } from '@/components/TokenIcon';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useVaultV2Deposit } from '@/hooks/useVaultV2Deposit';
import { formatBalance } from '@/utils/balance';
import { VaultDepositProcessModal } from './VaultDepositProcessModal';

type DepositToVaultModalProps = {
vaultAddress: Address;
vaultName: string;
assetAddress: Address;
assetSymbol: string;
assetDecimals: number;
chainId: number;
onClose: () => void;
onSuccess?: () => void;
};

export function DepositToVaultModal({
vaultAddress,
vaultName,
assetAddress,
assetSymbol,
assetDecimals,
chainId,
onClose,
onSuccess,
}: DepositToVaultModalProps): JSX.Element {
const { isConnected } = useAccount();
const [usePermit2Setting] = useLocalStorage('usePermit2', true);

const {
depositAmount,
setDepositAmount,
inputError,
setInputError,
tokenBalance,
isApproved,
permit2Authorized,
isLoadingPermit2,
depositPending,
approveAndDeposit,
signAndDeposit,
showProcessModal,
setShowProcessModal,
currentStep,
} = useVaultV2Deposit({
vaultAddress,
assetAddress,
assetSymbol,
assetDecimals,
chainId,
vaultName,
onSuccess,
});

return (
<>
<div
className="fixed inset-0 flex items-center justify-center bg-black/50"
style={{ zIndex: 50 }}
>
<div className="bg-surface relative w-full max-w-lg rounded p-6">
<div className="flex flex-col">
<button
type="button"
className="absolute right-2 top-2 text-secondary opacity-60 transition-opacity hover:opacity-100"
onClick={onClose}
>
<Cross1Icon />
</button>

<div className="mb-6 flex items-center justify-between">
<div className="flex flex-col">
<div className="flex items-center gap-2">
<TokenIcon
address={assetAddress}
chainId={chainId}
symbol={assetSymbol}
width={20}
height={20}
/>
Comment on lines +82 to +88
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove unsupported symbol prop from TokenIcon

TokenIcon doesn't accept a symbol prop.

  <TokenIcon
    address={assetAddress}
    chainId={chainId}
-   symbol={assetSymbol}
    width={20}
    height={20}
  />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TokenIcon
address={assetAddress}
chainId={chainId}
symbol={assetSymbol}
width={20}
height={20}
/>
<TokenIcon
address={assetAddress}
chainId={chainId}
width={20}
height={20}
/>
🤖 Prompt for AI Agents
In app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx
around lines 82 to 88, the TokenIcon component is being passed an unsupported
symbol prop; remove the symbol={assetSymbol} prop and only pass the supported
props (address, chainId, width, height) so the component receives valid props.

<span className="text-2xl">Deposit {assetSymbol}</span>
</div>
<span className="mt-1 text-sm text-gray-400">Deposit to {vaultName}</span>
</div>
</div>

{!isConnected ? (
<div className="flex justify-center py-4">
<AccountConnect />
</div>
) : (
<>
{/* Deposit Input Section */}
<div className="mt-12 space-y-4">
<div>
<div className="flex items-center justify-between">
<span className="opacity-80">Deposit amount</span>
<p className="font-inter text-xs opacity-50">
Balance: {formatBalance(tokenBalance ?? BigInt(0), assetDecimals)}{' '}
{assetSymbol}
</p>
</div>

<div className="mt-2 flex items-start justify-between">
<div className="relative flex-grow">
<Input
decimals={assetDecimals}
max={tokenBalance ?? BigInt(0)}
setValue={setDepositAmount}
setError={setInputError}
exceedMaxErrMessage="Insufficient Balance"
/>
{inputError && (
<p className="p-1 text-sm text-red-500 transition-opacity duration-200 ease-in-out">
{inputError}
</p>
)}
</div>

{!permit2Authorized || (!usePermit2Setting && !isApproved) ? (
<Button
isDisabled={!isConnected || isLoadingPermit2 || depositPending}
onPress={() => void approveAndDeposit()}
className="ml-2 min-w-32"
variant="cta"
>
Deposit
</Button>
Comment thread
antoncoding marked this conversation as resolved.
) : (
<Button
isDisabled={
!isConnected || depositPending || inputError !== null || !depositAmount
}
onPress={() => void signAndDeposit()}
className="ml-2 min-w-32"
variant="cta"
>
Deposit
</Button>
)}
</div>
</div>
</div>
</>
)}
</div>
</div>
</div>

{showProcessModal && (
<VaultDepositProcessModal
currentStep={currentStep}
onClose={() => setShowProcessModal(false)}
vaultName={vaultName}
assetSymbol={assetSymbol}
amount={depositAmount}
assetDecimals={assetDecimals}
usePermit2={usePermit2Setting}
/>
)}
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useMemo, useState } from 'react';
import { PlusIcon } from '@radix-ui/react-icons';
import { Address } from 'viem';
import { TokenIcon } from '@/components/TokenIcon';
import { formatBalance } from '@/utils/balance';
import { DepositToVaultModal } from './DepositToVaultModal';

type VaultTotalAssetsCardProps = {
totalAssets?: bigint
tokenDecimals?: number;
tokenSymbol?: string;
assetAddress?: Address;
chainId: number;
vaultAddress: Address;
vaultName: string;
onRefresh?: () => void;
};

export function TotalSupplyCard({
tokenDecimals,
tokenSymbol,
assetAddress,
chainId,
vaultAddress,
vaultName,
totalAssets,
onRefresh,
}: VaultTotalAssetsCardProps): JSX.Element {
const [showDepositModal, setShowDepositModal] = useState(false);


const totalAssetsLabel = useMemo(() => {
if (totalAssets === undefined || tokenDecimals === undefined) return '--';

try {
const numericAssets = formatBalance(totalAssets, tokenDecimals);
const formattedAssets = new Intl.NumberFormat('en-US', {
maximumFractionDigits: 2,
}).format(numericAssets);

return `${formattedAssets}${tokenSymbol ? ` ${tokenSymbol}` : ''}`.trim();
} catch (_error) {
return '--';
}
}, [tokenDecimals, tokenSymbol, totalAssets]);

const handleDepositSuccess = () => {
setShowDepositModal(false);
onRefresh?.();
};

return (
<>
<div className="rounded bg-surface p-4 shadow-sm">
<div className="flex items-center justify-between">
<span className="text-xs uppercase tracking-wide text-secondary">Total Assets</span>
{assetAddress && tokenSymbol && tokenDecimals !== undefined && (
<button
type="button"
onClick={() => setShowDepositModal(true)}
className="flex h-6 w-6 items-center justify-center rounded-full bg-primary/10 text-primary transition-colors hover:bg-primary/20"
aria-label="Deposit to vault"
>
<PlusIcon className="h-4 w-4" />
</button>
)}
</div>
<div className="mt-3 flex items-center gap-2 text-base text-primary">
<span className='text-base'>{totalAssetsLabel}</span>
{assetAddress && (
<TokenIcon address={assetAddress} chainId={chainId} width={20} height={20} />
)}
</div>
</div>

{showDepositModal && assetAddress && tokenSymbol && tokenDecimals !== undefined && (
<DepositToVaultModal
vaultAddress={vaultAddress}
vaultName={vaultName}
assetAddress={assetAddress}
assetSymbol={tokenSymbol}
assetDecimals={tokenDecimals}
chainId={chainId}
onClose={() => setShowDepositModal(false)}
onSuccess={handleDepositSuccess}
/>
)}
</>
);
}
Loading