Fix canonical vault routing and harden deep-link validation#82
Fix canonical vault routing and harden deep-link validation#82Kartikey44 wants to merge 3 commits intoStabilityNexus:mainfrom
Conversation
WalkthroughAdds a centralized vault/chain validation utility and applies runtime route validation across the vault page, explorer card, find-vault form, and InteractionClient call sites; routes are normalized to the canonical /{vaultId}?chainId={chainId} pattern and invalid params produce 404 or client errors. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as CardExplorer / FindVaultForm
participant Validator as validateVaultRoute
participant Router as Next Router
participant VaultPage as app/[vaultId]/page.tsx
participant Interaction as InteractionClient
User->>UI: submit vaultId + chainId
UI->>Validator: validateVaultRoute(vaultId, chainId)
alt valid
Validator-->>UI: { valid: true }
UI->>Router: navigate to /{vaultId}?chainId={chainId}
Router->>VaultPage: render with params & searchParams
VaultPage->>Validator: validateVaultRoute(vaultId, chainId)
alt valid
Validator-->>VaultPage: { valid: true }
VaultPage->>Interaction: render InteractionClient(vaultId, chainId)
Interaction-->>User: vault UI
else invalid
Validator-->>VaultPage: { valid: false }
VaultPage-->>User: notFound() (404)
end
else invalid
Validator-->>UI: { valid: false, error }
UI-->>User: show error toast / inline error
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 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: 4
🧹 Nitpick comments (1)
app/[vaultId]/page.tsx (1)
17-17: Coercing undefined to NaN requires validation to catch.When
searchParams.chainIdis absent,Number(undefined)returnsNaN. The subsequent validation correctly identifies this as invalid, but the intermediate NaN state could be made more explicit.Consider making the undefined case explicit:
- const chainId = Number(searchParams.chainId) + const chainId = searchParams.chainId ? Number(searchParams.chainId) : NaNThis makes the intent clearer without changing behavior.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/[vaultId]/page.tsx(1 hunks)components/Explorer/CardExplorer.tsx(5 hunks)components/FindVault/FindVaultForm.tsx(2 hunks)utils/validation.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
app/[vaultId]/page.tsx (1)
utils/validation.ts (1)
validateVaultRoute(13-26)
components/FindVault/FindVaultForm.tsx (1)
utils/validation.ts (1)
validateVaultRoute(13-26)
components/Explorer/CardExplorer.tsx (3)
utils/props.ts (1)
vaultsProps(1-9)utils/validation.ts (1)
validateVaultRoute(13-26)utils/chains.ts (2)
getChainColor(224-226)getChainName(179-181)
🔇 Additional comments (7)
utils/validation.ts (2)
5-7: LGTM! Address validation uses viem's battle-testedisAddress.The function correctly delegates to viem's
isAddress, which handles both checksummed and non-checksummed Ethereum addresses.
13-26: Solid centralized validation with clear error messages.The function correctly validates both address and chain ID, returning structured error objects that consumers can use for user feedback. The integration across
FindVaultForm,CardExplorer, and the vault page ensures consistent route validation.components/FindVault/FindVaultForm.tsx (3)
31-45: Excellent validation integration with clear user feedback.The function correctly converts the chainId to a number, validates both inputs using
validateVaultRoute, and provides user-facing error messages before navigating to the canonical route. The error state is properly cleared on success.
92-92: Good practice trimming whitespace from address input.Trimming prevents accidental leading/trailing spaces from invalidating otherwise correct addresses.
97-101: Clear error feedback improves user experience.The conditional error block provides immediate, visible feedback when validation fails, with appropriate styling to draw attention.
app/[vaultId]/page.tsx (1)
19-23: Server-side validation guard prevents invalid routes from rendering.Calling
validateVaultRoutebefore rendering and invokingnotFound()on failure provides defense-in-depth by rejecting bad routes at the page level, complementing client-side validation in forms and navigation handlers.components/Explorer/CardExplorer.tsx (1)
53-70: Robust validation with user-friendly error feedback.The handler validates the vault route before navigation and displays a descriptive toast message when validation fails, preventing navigation to invalid routes. The canonical route format
/${vaultAddress}?chainId=${chainId}aligns with the PR's routing strategy.
| <Input | ||
| id='chain-id' | ||
| type='number' | ||
| placeholder='e.g., 1 (Ethereum), 534351 (Scroll Sepolia)' | ||
| value={chainId || ''} | ||
| onChange={e => setChainId(Number(e.target.value))} | ||
| className="bg-background/50 backdrop-blur-sm border-primary/30 focus:border-primary/60 | ||
| transition-all duration-300 hover:border-primary/50 text-foreground placeholder:text-muted-foreground" | ||
| type="number" | ||
| placeholder="e.g., 1 (Ethereum), 534351 (Scroll Sepolia)" | ||
| value={chainId} | ||
| onChange={e => | ||
| setChainId(e.target.value ? Number(e.target.value) : '') | ||
| } | ||
| className="bg-background/50 backdrop-blur-sm border-primary/30" | ||
| /> |
There was a problem hiding this comment.
Input allows non-numeric characters resulting in NaN.
When a user types non-numeric text (e.g., "abc"), Number("abc") returns NaN, which is then stored in chainId. While validation later catches this, the UX could be improved by either:
- Restricting input to digits only via
patternor input filtering - Showing immediate feedback when non-numeric input is detected
Consider this improvement for immediate validation feedback:
<Input
type="number"
placeholder="e.g., 1 (Ethereum), 534351 (Scroll Sepolia)"
value={chainId}
onChange={e =>
- setChainId(e.target.value ? Number(e.target.value) : '')
+ {
+ const value = e.target.value
+ if (!value) {
+ setChainId('')
+ } else {
+ const num = Number(value)
+ if (!isNaN(num)) {
+ setChainId(num)
+ }
+ }
+ }
}
className="bg-background/50 backdrop-blur-sm border-primary/30"
/>📝 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.
| <Input | |
| id='chain-id' | |
| type='number' | |
| placeholder='e.g., 1 (Ethereum), 534351 (Scroll Sepolia)' | |
| value={chainId || ''} | |
| onChange={e => setChainId(Number(e.target.value))} | |
| className="bg-background/50 backdrop-blur-sm border-primary/30 focus:border-primary/60 | |
| transition-all duration-300 hover:border-primary/50 text-foreground placeholder:text-muted-foreground" | |
| type="number" | |
| placeholder="e.g., 1 (Ethereum), 534351 (Scroll Sepolia)" | |
| value={chainId} | |
| onChange={e => | |
| setChainId(e.target.value ? Number(e.target.value) : '') | |
| } | |
| className="bg-background/50 backdrop-blur-sm border-primary/30" | |
| /> | |
| <Input | |
| type="number" | |
| placeholder="e.g., 1 (Ethereum), 534351 (Scroll Sepolia)" | |
| value={chainId} | |
| onChange={e => | |
| { | |
| const value = e.target.value | |
| if (!value) { | |
| setChainId('') | |
| } else { | |
| const num = Number(value) | |
| if (!isNaN(num)) { | |
| setChainId(num) | |
| } | |
| } | |
| } | |
| } | |
| className="bg-background/50 backdrop-blur-sm border-primary/30" | |
| /> |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
app/[vaultId]/InteractionClient.tsx (1)
45-61: Avoid invalid “0x0” sentinel addresses leaking into UI/links
'0x0'isn’t a valid 20-byte address; it can produce broken explorer links or downstream formatting issues if rendered before real data arrives. Consider using the canonical zero-address string.- const [vaultCreator, setVaultCreator] = useState<`0x${string}`>('0x0') - const [coinAddress, setCoinAddress] = useState<`0x${string}`>('0x0') + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' as const + const [vaultCreator, setVaultCreator] = useState<`0x${string}`>(ZERO_ADDRESS) + const [coinAddress, setCoinAddress] = useState<`0x${string}`>(ZERO_ADDRESS) const [vault, setVault] = useState<vaultsProps>({ - coinAddress: '0x0', + coinAddress: ZERO_ADDRESS, coinName: '', coinSymbol: '', hodlCoinSymbol: '', decimals: 0, vaultAddress: vaultAddress, chainId, })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/[vaultId]/InteractionClient.tsx(5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/[vaultId]/InteractionClient.tsx (4)
utils/props.ts (1)
vaultsProps(1-9)utils/indexedDB.ts (1)
indexedDBManager(787-787)utils/chains.ts (1)
getChainName(179-181)components/Vault/VaultInformation.tsx (1)
VaultInformation(8-202)
🔇 Additional comments (2)
app/[vaultId]/InteractionClient.tsx (2)
28-37: Props-based routing input is a good simplification
MovingvaultId/chainIdinto explicit props (vs parsing search params inside) makes the component easier to reason about and aligns with server-side route validation.
79-177: [Rewritten review comment]
[Classification tag]
app/[vaultId]/InteractionClient.tsx
Outdated
| const publicClient = getPublicClient(config as any, { chainId }) | ||
| if (!publicClient) throw new Error('No public client') | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find and display package.json content (especially versions)
echo "=== WAGMI/VIEM VERSIONS ==="
fd -a 'package.json' | head -1 | xargs cat | python3 -m json.tool | grep -A 2 -B 2 '"wagmi"\|"viem"\|"@wagmi"'
# 2) Find all getPublicClient usages to check signature consistency
echo -e "\n=== GETPUBLICCLIENT USAGES ==="
rg -n 'getPublicClient\s*\(' --type ts --type tsx -B 3 -A 3Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 168
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Read package.json directly (simpler approach)
echo "=== PACKAGE.JSON WAGMI/VIEM VERSIONS ==="
if [ -f package.json ]; then
cat package.json | grep -E '"(wagmi|viem|@wagmi)' | head -10
fi
# 2) Read the specific file mentioned in the review
echo -e "\n=== INTERACTIONCLIENT.TSX CONTEXT (Lines 100-120) ==="
if [ -f "app/[vaultId]/InteractionClient.tsx" ]; then
sed -n '100,120p' "app/[vaultId]/InteractionClient.tsx"
fi
# 3) Find getPublicClient calls - simpler search
echo -e "\n=== GETPUBLICCLIENT CALLS ==="
rg 'getPublicClient' --type ts --type tsx --max-count 10 -nRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 998
🌐 Web query:
wagmi v2 getPublicClient signature documentation
💡 Result:
The Wagmi v2 getPublicClient API:
-
Import:
import { getPublicClient } from '@wagmi/core'. [1] -
Usage / signature (TypeScript):
const publicClient = getPublicClient(config?, { chainId?: number }); // returns PublicClient | undefined. [1][2] -
Types referenced:
GetClientParameters (for the params) and GetPublicClientReturnType (PublicClient | undefined). [1]
Sources:
[1] Wagmi docs — getPublicClient. [2] Wagmi v1.x docs (migration / usage reference).
Remove as any cast and properly type the config parameter
The getPublicClient(config, { chainId }) signature is correct for wagmi v2.13.3, but masking config with as any prevents TypeScript from catching type errors. Either import and use the proper config type (likely from @wagmi/core) or use proper type inference instead of the cast.
🤖 Prompt for AI Agents
In app/[vaultId]/InteractionClient.tsx around lines 109-111, remove the unsafe
`as any` cast on `config` and correctly type it: import the proper wagmi config
type from the wagmi/@wagmi/core package (whichever export your version exposes),
annotate the `config` variable/parameter with that type so TypeScript can
validate it, and then call `getPublicClient(config, { chainId })` without
casting; ensure any mismatched fields are fixed to match the imported type.
| <ActionsVault | ||
| vault={vault} | ||
| priceHodl={balances.priceHodl} | ||
| coinBalance={balances.coinBalance} | ||
| hodlCoinBalance={balances.hodlCoinBalance} | ||
| getBalances={() => {}} | ||
| /> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "*.tsx" -o -name "*.ts" | xargs grep -l "ActionsVault" | head -20Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 150
🏁 Script executed:
cat -n ./components/Vault/Actions.tsxRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 1201
🏁 Script executed:
find . -type f -name "HodlBox*" -o -name "UnhodlBox*" | head -10Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 145
🏁 Script executed:
cat -n ./components/Vault/HodlBox.tsxRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 12124
🏁 Script executed:
cat -n ./components/Vault/UnhodlBox.tsxRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 13191
🏁 Script executed:
cat -n ./app/[vaultId]/InteractionClient.tsx | head -240 | tail -50Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 1662
🏁 Script executed:
head -100 ./app/[vaultId]/InteractionClient.tsxRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 3031
🏁 Script executed:
sed -n '100,190p' ./app/[vaultId]/InteractionClient.tsxRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 2529
🏁 Script executed:
rg "getBalances|setBalances" ./app/[vaultId]/InteractionClient.tsx -A 3 -B 3Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 410
🏁 Script executed:
rg "setBalances" ./app/[vaultId]/InteractionClient.tsx -B 5 -A 2Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 238
🏁 Script executed:
rg "coinBalance|hodlCoinBalance" ./app/[vaultId]/InteractionClient.tsxRepository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 219
🏁 Script executed:
find . -type f -name "*.tsx" -o -name "*.ts" | xargs grep -l "readContract.*balanceOf" | head -10Repository: StabilityNexus/hodlCoin-Solidity-WebUI
Length of output: 64
getBalances must be implemented or made optional with fallback—currently broken post-transaction balance refresh
HodlBox (line 132) and UnhodlBox (line 137) both call await getBalances() after stake/unstake transactions to refresh balances. Passing () => {} leaves balances stale, breaking the post-transaction UI update flow. Either provide a working refresh function from the parent or make the prop optional with an internal refetch mechanism.
🤖 Prompt for AI Agents
In app/[vaultId]/InteractionClient.tsx around lines 224-230, getBalances is
passed as a no-op (() => {}) to ActionsVault which breaks post-transaction
balance refresh because HodlBox and UnhodlBox call await getBalances(); replace
the no-op with the real refresh function from the parent (pass the actual
balances refetch function used in this component) OR change ActionsVault's prop
to optional and implement an internal fallback: update the prop type to
getBalances?: () => Promise<void>, and inside ActionsVault call (getBalances ??
internalRefetch)(). Ensure the parent either provides the real async refetch
implementation or ActionsVault performs its own balance refetch when getBalances
is undefined.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
components/FindVault/FindVaultForm.tsx (1)
54-61: Input still allows NaN when non-numeric text is entered.Similar to the previous review comment, when non-numeric text is pasted or entered (despite
type="number"),Number(e.target.value)returnsNaN, which is stored in thechainIdstate. This creates a poor user experience with delayed error feedback only appearing on submit.Consider this approach for immediate validation:
<Input placeholder="Chain ID" type="number" value={chainId} onChange={e => { - setChainId(e.target.value ? Number(e.target.value) : '') + const value = e.target.value + if (!value) { + setChainId('') + } else { + const num = Number(value) + if (!isNaN(num)) { + setChainId(num) + } + } }} />
🧹 Nitpick comments (3)
components/FindVault/FindVaultForm.tsx (2)
63-67: Trim on every keystroke may hinder typing flow.The
.trim()on line 66 executes on every keystroke, preventing users from typing spaces even temporarily (e.g., pasting addresses with spaces, or natural typing patterns). Consider trimming only on blur or during validation.<Input placeholder="Vault Address" value={vaultAddress} - onChange={e => setVaultAddress(e.target.value.trim())} + onChange={e => setVaultAddress(e.target.value)} + onBlur={e => setVaultAddress(e.target.value.trim())} />
69-69: Consider improving error message accessibility.The error message is displayed using a plain
<p>tag without semantic or accessibility attributes. For better accessibility and consistency, consider using a proper alert component or adding appropriate ARIA attributes.-{error && <p className="text-red-500">{error}</p>} +{error && ( + <div role="alert" className="text-sm text-red-500 bg-red-50 p-2 rounded"> + {error} + </div> +)}components/Explorer/CardExplorer.tsx (1)
40-52: Validation in explorer context should log unexpected failures.While defensive validation is good practice, if validation fails here it indicates the explorer is displaying corrupt or invalid vault data from the backend. This scenario should never occur in production and suggests a data integrity issue.
Consider distinguishing between expected validation failures (user input) and unexpected ones (data corruption):
const handleContinue = () => { const validation = validateVaultRoute( vault.vaultAddress, vault.chainId ) if (!validation.valid) { + console.error('Explorer displayed invalid vault:', { + vaultAddress: vault.vaultAddress, + chainId: vault.chainId, + error: validation.error + }) toast({ title: 'Invalid vault', variant: 'destructive' }) return } router.push(`/${vault.vaultAddress}?chainId=${vault.chainId}`) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/[vaultId]/InteractionClient.tsx(1 hunks)app/[vaultId]/page.tsx(1 hunks)components/Explorer/CardExplorer.tsx(1 hunks)components/FindVault/FindVaultForm.tsx(1 hunks)utils/validation.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- utils/validation.ts
- app/[vaultId]/page.tsx
- app/[vaultId]/InteractionClient.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
components/FindVault/FindVaultForm.tsx (3)
utils/validation.ts (1)
validateVaultRoute(35-48)components/ui/alert-dialog.tsx (8)
AlertDialog(130-130)AlertDialogTrigger(133-133)AlertDialogContent(134-134)AlertDialogHeader(135-135)AlertDialogTitle(137-137)AlertDialogFooter(136-136)AlertDialogCancel(140-140)AlertDialogAction(139-139)components/ui/input.tsx (1)
Input(25-25)
components/Explorer/CardExplorer.tsx (7)
utils/props.ts (1)
vaultsProps(1-9)utils/favorites.ts (2)
useFavorites(243-284)isFavorite(77-101)utils/validation.ts (1)
validateVaultRoute(35-48)components/ui/use-toast.ts (1)
toast(194-194)components/ui/card.tsx (3)
Card(79-79)CardHeader(79-79)CardContent(79-79)utils/chains.ts (2)
getChainColor(224-226)getChainName(179-181)components/ui/button.tsx (1)
Button(56-56)
🔇 Additional comments (2)
components/Explorer/CardExplorer.tsx (2)
12-12: Great improvement: centralized chain utilities now used.The import of
getChainColorfrom@/utils/chainsaddresses the previous review comment about code duplication. This maintains a single source of truth for chain-related styling.
54-69: Clean, semantic card structure.The simplified UI follows good practices with semantic HTML, proper use of centralized utilities (
getChainName,getChainColor), and an accessible button with clear action text.
| import { vaultsProps } from '@/utils/props' | ||
| import { useRouter } from 'next/navigation' | ||
| import { ArrowRight, TrendingUp, Star, StarOff} from 'lucide-react' | ||
| import { ArrowRight, Star, StarOff } from 'lucide-react' |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove unused icon imports.
The Star and StarOff icons are imported but never rendered in the component. The favorite functionality tracking exists (lines 24-38) but the UI elements have been removed.
-import { ArrowRight, Star, StarOff } from 'lucide-react'
+import { ArrowRight } from 'lucide-react'📝 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.
| import { ArrowRight, Star, StarOff } from 'lucide-react' | |
| import { ArrowRight } from 'lucide-react' |
🤖 Prompt for AI Agents
In components/Explorer/CardExplorer.tsx around line 7, the Star and StarOff
icons are imported but unused; remove them from the import statement (leave
ArrowRight) to clean up unused imports, or if the favorite UI should exist,
re-add the favorite button markup that uses Star/StarOff and wire it to the
existing favorite state/handlers on lines ~24-38 so the icons are actually
rendered.
| const [isFavorited, setIsFavorited] = useState(false) | ||
| const [favoriteLoading, setFavoriteLoading] = useState(false) | ||
| const chainId = vault.chainId | ||
| const router = useRouter() | ||
| const { isFavorite, toggleFavorite } = useFavorites() | ||
| const { address: userAddress } = useAccount() | ||
| const { address } = useAccount() | ||
|
|
||
| const checkFavoriteStatus = useCallback(async () => { | ||
| if (!userAddress) { | ||
| setIsFavorited(false) | ||
| return | ||
| } | ||
|
|
||
| try { | ||
| const favoriteStatus = await isFavorite(vault.vaultAddress, vault.chainId, userAddress) | ||
| setIsFavorited(favoriteStatus) | ||
| } catch (error) { | ||
| console.error('Error checking favorite status:', error) | ||
| setIsFavorited(false) | ||
| } | ||
| }, [vault.vaultAddress, vault.chainId, userAddress, isFavorite]) | ||
| const checkFavorite = useCallback(async () => { | ||
| if (!address) return | ||
| setIsFavorited( | ||
| await isFavorite(vault.vaultAddress, vault.chainId, address) | ||
| ) | ||
| }, [vault, address, isFavorite]) | ||
|
|
||
| useEffect(() => { | ||
| checkFavoriteStatus() | ||
| }, [checkFavoriteStatus]) | ||
| checkFavorite() | ||
| }, [checkFavorite]) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove unused favorite tracking logic.
The favorite state and checking logic execute on every render, but the state is never used in the UI (lines 54-69 show no favorite indicator or toggle button). The imported toggleFavorite function is also unused.
Remove the unused code:
export default function CardExplorer({ vault }: { vault: ExtendedVaultProps }) {
- const [isFavorited, setIsFavorited] = useState(false)
const router = useRouter()
- const { isFavorite, toggleFavorite } = useFavorites()
- const { address } = useAccount()
-
- const checkFavorite = useCallback(async () => {
- if (!address) return
- setIsFavorited(
- await isFavorite(vault.vaultAddress, vault.chainId, address)
- )
- }, [vault, address, isFavorite])
-
- useEffect(() => {
- checkFavorite()
- }, [checkFavorite])
const handleContinue = () => {Also remove unused imports:
-import { useFavorites } from '@/utils/favorites'
-import { useAccount } from 'wagmi'🤖 Prompt for AI Agents
In components/Explorer/CardExplorer.tsx around lines 24 to 38, remove the unused
favorites tracking logic: delete the isFavorited state, the checkFavorite
useCallback, the useEffect that calls it, and remove the unused toggleFavorite
and isFavorite references; also remove the useAccount/address usage and any
related imports (useFavorites, useAccount) if they are no longer used elsewhere
in the file, and adjust the hook dependency list/refs accordingly so lint and
build errors are resolved.
| const handleContinue = () => { | ||
| if (vaultAddress && chainId) { | ||
| router.push(`/v?chainId=${chainId}&vault=${vaultAddress}`) | ||
| const validation = validateVaultRoute( | ||
| vaultAddress, | ||
| Number(chainId) | ||
| ) | ||
|
|
||
| if (!validation.valid) { | ||
| setError(validation.error!) | ||
| return | ||
| } | ||
|
|
||
| router.push(`/${vaultAddress}?chainId=${chainId}`) | ||
| } |
There was a problem hiding this comment.
Empty chainId produces 0, potentially bypassing validation.
When chainId is an empty string (initial state), Number(chainId) at line 35 evaluates to 0, which is then passed to validateVaultRoute. If the validation logic doesn't explicitly reject chain ID 0, this could lead to invalid navigation attempts.
Apply this diff to ensure empty input is caught:
const handleContinue = () => {
+ if (!vaultAddress || chainId === '') {
+ setError('Please enter both Chain ID and Vault Address')
+ return
+ }
+
const validation = validateVaultRoute(
vaultAddress,
Number(chainId)
)
if (!validation.valid) {
setError(validation.error!)
return
}
+ setError(null)
router.push(`/${vaultAddress}?chainId=${chainId}`)
}Note: Also added setError(null) before navigation to clear any previous error state.
🤖 Prompt for AI Agents
In components/FindVault/FindVaultForm.tsx around lines 32 to 44, Number(chainId)
turns an empty string into 0 which can bypass validation; update handleContinue
to first check for an empty chainId (or that Number(chainId) is NaN) and
setError with a suitable message and return if invalid, only then parse chainId
to a Number and call validateVaultRoute; also clear any previous error with
setError(null) immediately before calling router.push so navigation isn’t
blocked by stale errors.
Summary
This PR fixes broken vault navigation caused by the legacy
/v?...routeand enforces a single canonical vault routing format.
Changes
/v?...navigation with/${vaultAddress}?chainId=<id>Benefits
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.