diff --git a/packages/app/schemas/StrategyMetadata.ts b/packages/app/schemas/StrategyMetadata.ts index d31c22b..83f215e 100644 --- a/packages/app/schemas/StrategyMetadata.ts +++ b/packages/app/schemas/StrategyMetadata.ts @@ -1,4 +1,4 @@ -import z from 'zod' +import { z } from 'zod' import { AddressSchema } from '.' export const StrategyMetadataSchema = z.object({ @@ -40,8 +40,10 @@ export const StrategyMetadataSchema = z.object({ 'League DAO', 'Lido Finance', 'MakerDAO', + 'Morpho', 'Mushroom Finance', 'Notional Finance', + 'Pendle', 'Pool Together', 'Scream', 'Solidex Finance', @@ -63,6 +65,8 @@ export const StrategyMetadataSchema = z.object({ 'veDAO', ]), ), + githubCode: z.string().optional(), + strategyType: z.string().optional(), }) export type StrategyMetadata = z.infer diff --git a/packages/app/schemas/cms.ts b/packages/app/schemas/cms.ts index d38aad4..30437b5 100644 --- a/packages/app/schemas/cms.ts +++ b/packages/app/schemas/cms.ts @@ -26,7 +26,7 @@ export const collections = { schema: StrategyMetadataSchema, displayName: 'Strategies', icon: 'strategy', - searchFields: ['name', 'address'] as const, + searchFields: ['name', 'address', 'githubCode', 'strategyType'] as const, filterableBooleanFields: [] as const, listItemTemplate: 'strategy' as const, }, diff --git a/packages/app/schemas/index.ts b/packages/app/schemas/index.ts index 88f02ca..023efca 100644 --- a/packages/app/schemas/index.ts +++ b/packages/app/schemas/index.ts @@ -1,3 +1,3 @@ -import z from 'zod' +import { z } from 'zod' export const AddressSchema = z.string().regex(/^0x[0-9a-fA-F]{40}$/) diff --git a/packages/app/scripts/etl-vault-metadata-from-ydaemon.ts b/packages/app/scripts/etl-vault-metadata-from-ydaemon.ts index 456053c..3b4c419 100644 --- a/packages/app/scripts/etl-vault-metadata-from-ydaemon.ts +++ b/packages/app/scripts/etl-vault-metadata-from-ydaemon.ts @@ -16,7 +16,7 @@ export const YDaemonVaultMetadataSchema = z.object({ chainID: z.number(), address: AddressSchema, registry: optionalString(AddressSchema), - type: z.enum(['Yearn Vault', 'Experimental Yearn Vault', 'Automated Yearn Vault', 'Single Strategy']), + type: z.enum(['Yearn Vault', 'Experimental Yearn Vault', 'Automated Yearn Vault', 'Single Strategy', 'None']), kind: optionalString(z.enum(['Multi Strategy', 'Legacy', 'Single Strategy'])), endorsed: z.boolean().optional(), metadata: z diff --git a/packages/app/src/components/SchemaForm.tsx b/packages/app/src/components/SchemaForm.tsx index 30e8512..35de36c 100644 --- a/packages/app/src/components/SchemaForm.tsx +++ b/packages/app/src/components/SchemaForm.tsx @@ -1,7 +1,7 @@ import type React from 'react' import type { ReactNode } from 'react' import { createContext, useContext, useEffect, useState } from 'react' -import z from 'zod' +import { z } from 'zod' import { cn } from '../../lib/cn' import Input from './eg/elements/Input' import Switch from './eg/elements/Switch' diff --git a/packages/app/src/components/eg/ChainIcon.tsx b/packages/app/src/components/eg/ChainIcon.tsx index c68cf0c..2355906 100644 --- a/packages/app/src/components/eg/ChainIcon.tsx +++ b/packages/app/src/components/eg/ChainIcon.tsx @@ -1,6 +1,6 @@ import { getChainIconUrl } from '../../../lib/assets' import { chains } from '../../../lib/chains' -import { cn } from './cn' +import { cn } from '../../../lib/cn' import ImgOrBg from './ImgOrBg' type Props = { diff --git a/packages/app/src/components/eg/ChainSelect/index.tsx b/packages/app/src/components/eg/ChainSelect/index.tsx index a63630f..cccd4a9 100644 --- a/packages/app/src/components/eg/ChainSelect/index.tsx +++ b/packages/app/src/components/eg/ChainSelect/index.tsx @@ -1,8 +1,8 @@ import { memo, useMemo } from 'react' import { PiCaretDownBold, PiFireSimpleFill } from 'react-icons/pi' import { chains } from '../../../../lib/chains' +import { cn } from '../../../../lib/cn' import ChainIcon from '../ChainIcon' -import { cn } from '../cn' import { HoverCard, HoverCardTrigger } from '../HoverCard' import { useMounted } from '../hooks/useMounted' import FlyInFromBottom from '../motion/FlyInFromBottom' diff --git a/packages/app/src/components/eg/Footer/index.tsx b/packages/app/src/components/eg/Footer/index.tsx index 7528cab..3108e69 100644 --- a/packages/app/src/components/eg/Footer/index.tsx +++ b/packages/app/src/components/eg/Footer/index.tsx @@ -1,5 +1,5 @@ import { forwardRef, type HTMLAttributes } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' export type FooterProps = HTMLAttributes & { className?: string diff --git a/packages/app/src/components/eg/HoverCard/index.tsx b/packages/app/src/components/eg/HoverCard/index.tsx index 8296d6e..e0aa979 100644 --- a/packages/app/src/components/eg/HoverCard/index.tsx +++ b/packages/app/src/components/eg/HoverCard/index.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react' import { useCallback } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' import Card from '../elements/Card' import { useHoverCard } from './useHoverCard' diff --git a/packages/app/src/components/eg/HoverSelect/index.tsx b/packages/app/src/components/eg/HoverSelect/index.tsx index d469160..b4e48e4 100644 --- a/packages/app/src/components/eg/HoverSelect/index.tsx +++ b/packages/app/src/components/eg/HoverSelect/index.tsx @@ -1,6 +1,6 @@ import { type ReactNode, useCallback, useMemo } from 'react' import { PiCaretDownBold } from 'react-icons/pi' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' import { HoverCard, HoverCardTrigger } from '../HoverCard' import { type SelectOption, useHoverSelect } from './useHoverSelect' diff --git a/packages/app/src/components/eg/ImgOrBg.tsx b/packages/app/src/components/eg/ImgOrBg.tsx index 06cce33..73cbdcf 100644 --- a/packages/app/src/components/eg/ImgOrBg.tsx +++ b/packages/app/src/components/eg/ImgOrBg.tsx @@ -1,6 +1,6 @@ import type { ImgHTMLAttributes } from 'react' import { useMemo, useState } from 'react' -import { cn } from './cn' +import { cn } from '../../../lib/cn' interface ImgOrBg extends ImgHTMLAttributes { bgClassName?: string diff --git a/packages/app/src/components/eg/Skeleton.tsx b/packages/app/src/components/eg/Skeleton.tsx index 73271e0..11dc79c 100644 --- a/packages/app/src/components/eg/Skeleton.tsx +++ b/packages/app/src/components/eg/Skeleton.tsx @@ -1,4 +1,4 @@ -import { cn } from './cn' +import { cn } from '../../../lib/cn' export default function Skeleton({ className, diff --git a/packages/app/src/components/eg/TokenIcon.tsx b/packages/app/src/components/eg/TokenIcon.tsx index 6eb4ecd..5aafa95 100644 --- a/packages/app/src/components/eg/TokenIcon.tsx +++ b/packages/app/src/components/eg/TokenIcon.tsx @@ -1,6 +1,6 @@ import { getTokenIconUrl } from '../../../lib/assets' +import { cn } from '../../../lib/cn' import ChainIcon from './ChainIcon' -import { cn } from './cn' import ImgOrBg from './ImgOrBg' type Props = { diff --git a/packages/app/src/components/eg/cn.ts b/packages/app/src/components/eg/cn.ts deleted file mode 100644 index d32b0fe..0000000 --- a/packages/app/src/components/eg/cn.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type ClassValue, clsx } from 'clsx' -import { twMerge } from 'tailwind-merge' - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} diff --git a/packages/app/src/components/eg/elements/Button.tsx b/packages/app/src/components/eg/elements/Button.tsx index eb764f6..585f145 100644 --- a/packages/app/src/components/eg/elements/Button.tsx +++ b/packages/app/src/components/eg/elements/Button.tsx @@ -1,5 +1,5 @@ import { type ButtonHTMLAttributes, forwardRef } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' export type Variant = 'accent' | 'primary' | 'secondary' | 'error' | 'busy' diff --git a/packages/app/src/components/eg/elements/Card.tsx b/packages/app/src/components/eg/elements/Card.tsx index 01da90e..8cc423c 100644 --- a/packages/app/src/components/eg/elements/Card.tsx +++ b/packages/app/src/components/eg/elements/Card.tsx @@ -1,6 +1,6 @@ import type { HTMLAttributes, ReactNode } from 'react' import { forwardRef } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' export type CardProps = HTMLAttributes & { className?: string diff --git a/packages/app/src/components/eg/elements/Input.tsx b/packages/app/src/components/eg/elements/Input.tsx index f02b1b2..04eee25 100644 --- a/packages/app/src/components/eg/elements/Input.tsx +++ b/packages/app/src/components/eg/elements/Input.tsx @@ -1,5 +1,5 @@ import { forwardRef, type InputHTMLAttributes } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' export const InputClassName = cn(` relative px-4 py-3 diff --git a/packages/app/src/components/eg/elements/ListItem.tsx b/packages/app/src/components/eg/elements/ListItem.tsx index 91c031f..f19fbc8 100644 --- a/packages/app/src/components/eg/elements/ListItem.tsx +++ b/packages/app/src/components/eg/elements/ListItem.tsx @@ -1,6 +1,6 @@ import type { HTMLAttributes } from 'react' import { forwardRef } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' export type ListItemProps = HTMLAttributes & { className?: string diff --git a/packages/app/src/components/eg/elements/Switch.tsx b/packages/app/src/components/eg/elements/Switch.tsx index 44570fc..b83fb94 100644 --- a/packages/app/src/components/eg/elements/Switch.tsx +++ b/packages/app/src/components/eg/elements/Switch.tsx @@ -1,5 +1,5 @@ import * as _Switch from '@radix-ui/react-switch' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' const Switch = ({ label, diff --git a/packages/app/src/components/eg/elements/Textarea.tsx b/packages/app/src/components/eg/elements/Textarea.tsx index eae62b0..50cb987 100644 --- a/packages/app/src/components/eg/elements/Textarea.tsx +++ b/packages/app/src/components/eg/elements/Textarea.tsx @@ -1,5 +1,5 @@ import { forwardRef, type TextareaHTMLAttributes } from 'react' -import { cn } from '../cn' +import { cn } from '../../../../lib/cn' import { InputClassName } from './Input' type Props = TextareaHTMLAttributes & { diff --git a/packages/app/src/components/eg/motion/FlyInFromBottom.tsx b/packages/app/src/components/eg/motion/FlyInFromBottom.tsx index 76434c9..4b896b6 100644 --- a/packages/app/src/components/eg/motion/FlyInFromBottom.tsx +++ b/packages/app/src/components/eg/motion/FlyInFromBottom.tsx @@ -1,7 +1,7 @@ import type { Transition } from 'framer-motion' import { motion } from 'framer-motion' import { useMemo } from 'react' -import { cn } from '../cn' +import { cn } from '../../../lib/cn' import { springs } from '../lib/motion' export default function FlyInFromBottom({ diff --git a/packages/app/src/hooks/useStrategyMeta.ts b/packages/app/src/hooks/useStrategyMeta.ts deleted file mode 100644 index 63a3fd3..0000000 --- a/packages/app/src/hooks/useStrategyMeta.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { useSuspenseQuery } from '@tanstack/react-query' -import { useMemo } from 'react' -import { getCdnUrl } from '../../lib/cdn' -import { chains } from '../../lib/chains' -import { StrategyMetadataSchema } from '../../schemas/StrategyMetadata' - -export function useStrategyMeta() { - const query = useSuspenseQuery({ - queryKey: ['strategies-meta'], - queryFn: async () => { - const promises = Object.values(chains).map((chain) => fetch(`${getCdnUrl()}strategies/${chain.id}.json`)) - const jsonPromises = (await Promise.all(promises)).flatMap((result) => result.json()) - const jsons = await Promise.all(jsonPromises) - - const chainKeys = Object.keys(chains).map(Number) - const rawJsonChainMap: Record = {} - jsons.forEach((json, index) => { - const chainId = chains[chainKeys[index]].id - rawJsonChainMap[chainId] = json - }) - - return { flat: jsons.flat(), rawJsonChainMap } - }, - staleTime: 1000 * 60 * 5, - }) - - const strategies = useMemo(() => { - return query.data.flat.map((d) => StrategyMetadataSchema.parse(d)) - }, [query.data.flat]) - - const sorted = useMemo(() => { - return strategies.sort((a, b) => { - if (a.chainId < b.chainId) return -1 - if (a.chainId > b.chainId) return 1 - if (a.name < b.name) return -1 - if (a.name > b.name) return 1 - return 0 - }) - }, [strategies]) - - return { - ...query, - strategies: sorted, - rawJsonChainMap: query.data.rawJsonChainMap, - } -} diff --git a/packages/app/src/hooks/useVaultMeta.ts b/packages/app/src/hooks/useVaultMeta.ts deleted file mode 100644 index c03e098..0000000 --- a/packages/app/src/hooks/useVaultMeta.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { useSuspenseQuery } from '@tanstack/react-query' -import { useMemo } from 'react' -import { getCdnUrl } from '../../lib/cdn' -import { chains } from '../../lib/chains' -import { VaultMetadataSchema } from '../../schemas/VaultMetadata' - -export function useVaultsMeta() { - const query = useSuspenseQuery({ - queryKey: ['vaults-meta'], - queryFn: async () => { - const promises = Object.values(chains).map((chain) => fetch(`${getCdnUrl()}vaults/${chain.id}.json`)) - const jsonPromises = (await Promise.all(promises)).flatMap((result) => result.json()) - const jsons = await Promise.all(jsonPromises) - - const chainKeys = Object.keys(chains).map(Number) - const rawJsonChainMap: Record = {} - jsons.forEach((json, index) => { - const chainId = chains[chainKeys[index]].id - rawJsonChainMap[chainId] = json - }) - - return { flat: jsons.flat(), rawJsonChainMap } - }, - staleTime: 1000 * 60 * 5, - }) - - const vaults = useMemo(() => { - return query.data.flat.map((d) => VaultMetadataSchema.parse(d)) - }, [query.data.flat]) - - const sortedVaults = useMemo(() => { - return vaults.sort((a, b) => { - if (a.chainId < b.chainId) return -1 - if (a.chainId > b.chainId) return 1 - if (a.name < b.name) return -1 - if (a.name > b.name) return 1 - return 0 - }) - }, [vaults]) - - return { - ...query, - vaults: sortedVaults, - rawJsonChainMap: query.data.rawJsonChainMap, - } -} diff --git a/packages/app/src/routes/Strategies.tsx b/packages/app/src/routes/Strategies.tsx deleted file mode 100644 index ed666a3..0000000 --- a/packages/app/src/routes/Strategies.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Suspense, useCallback, useEffect, useMemo, useState } from 'react' -import InfiniteScroll from 'react-infinite-scroll-component' -import type { StrategyMetadata } from '../../schemas/StrategyMetadata' -import BackItUp from '../components/BackItUp' -import Skeleton from '../components/eg/Skeleton' -import TokenIcon from '../components/eg/TokenIcon' -import Link from '../components/elements/Link' -import { useFinder } from '../components/Finder' -import { useStrategyMeta } from '../hooks/useStrategyMeta' -import { useToggleChainStore } from '../hooks/useToggleChainStore' - -const INFINTE_SCROLL_FRAME_SIZE = 20 - -function List() { - const { finderString } = useFinder() - const { toggledChains } = useToggleChainStore() - const { strategies } = useStrategyMeta() - - const filter: StrategyMetadata[] = useMemo(() => { - return strategies.filter( - (strategy: StrategyMetadata) => - toggledChains.has(strategy.chainId) && - (strategy.name.toLowerCase().includes(finderString.toLowerCase()) || - strategy.address.toLowerCase().includes(finderString.toLowerCase())), - ) - }, [strategies, finderString, toggledChains]) - - const [items, setItems] = useState(filter?.slice(0, INFINTE_SCROLL_FRAME_SIZE)) - useEffect(() => setItems(filter?.slice(0, INFINTE_SCROLL_FRAME_SIZE)), [filter]) - const hasMoreFrames = useMemo(() => items.length < filter.length, [items, filter]) - const fetchFrame = useCallback(() => { - setItems((prevItems) => [ - ...prevItems, - ...filter.slice(prevItems.length, prevItems.length + INFINTE_SCROLL_FRAME_SIZE), - ]) - }, [filter]) - - return ( - - {items.map((strategy: StrategyMetadata) => ( - - -
- {strategy.address.slice(0, 6)}..{strategy.address.slice(-6)} -
-
{strategy.name || 'No name onchain'}
- - ))} -
- ) -} - -function StrategiesSkeleton() { - return ( -
- - - - - - - - - -
- ) -} - -function Strategies() { - return ( -
- }> - - - -
- ) -} - -export default Strategies diff --git a/packages/app/src/routes/Strategy.tsx b/packages/app/src/routes/Strategy.tsx deleted file mode 100644 index 22c7f05..0000000 --- a/packages/app/src/routes/Strategy.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { useMutation } from '@tanstack/react-query' -import { Suspense } from 'react' -import { PiGitPullRequest } from 'react-icons/pi' -import { useParams } from 'react-router-dom' -import { chains } from '../../lib/chains' -import { StrategyMetadataSchema } from '../../schemas/StrategyMetadata' -import type { VaultMetadata } from '../../schemas/VaultMetadata' -import Button from '../components/eg/elements/Button' -import Skeleton from '../components/eg/Skeleton' -import GithubSignIn, { useGithubUser } from '../components/GithubSignIn' -import MetaData, { MetaDataProvider, useMetaData } from '../components/SchemaForm' -import { useStrategyMeta } from '../hooks/useStrategyMeta' - -function PullRequestButton() { - const { o: vault, isDirty, formState } = useMetaData() - const { rawJsonChainMap } = useStrategyMeta() - - const createPullRequest = useMutation({ - mutationFn: async () => { - const original = rawJsonChainMap[vault.chainId] - const path = `packages/cdn/strategies/${vault.chainId}.json` - - // Find and replace the specific vault - const updatedArray = original.map((vaultObj: VaultMetadata) => - vaultObj.address.toLowerCase() === vault.address.toLowerCase() ? formState : vaultObj, - ) - - const response = await fetch('/api/pr', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - token: sessionStorage.getItem('github_token'), - path, - contents: JSON.stringify(updatedArray, null, 2), - }), - }) - - const result = await response.json() - - if (!result.success) { - throw new Error(result.error || 'Failed to create pull request') - } - - return result - }, - onSuccess: (data) => { - window.open(data.pullRequestUrl, '_blank') - }, - onError: (error) => { - console.error('PR creation failed:', error) - alert(`Failed to create pull request: ${error.message}`) - }, - }) - - // Throw a promise to trigger Suspense when pending - if (createPullRequest.isPending) { - throw new Promise(() => {}) // This will never resolve, keeping Suspense active - } - - return ( - - ) -} - -function StrategyDetails() { - const { signedIn } = useGithubUser() - const { o: strategy } = useMetaData() - return ( -
-
-

{strategy.name || 'No name onchain'}

-
- chain: {chains[strategy.chainId]?.name} ({strategy.chainId}) -
-
address: {strategy.address}
-
- - }> - {signedIn && } - {!signedIn && } - -
- ) -} - -function Provider({ children }: { children: React.ReactNode }) { - const { chainId, address } = useParams() - const { strategies } = useStrategyMeta() - - const strategy = strategies.find( - (v) => v.chainId.toString() === chainId && v.address.toLowerCase() === address?.toLowerCase(), - ) - - if (!strategy) { - throw new Error('Stratgy not found') - } - - return ( - - {children} - - ) -} - -function StrategySkeleton() { - return ( -
- - - - - -
- ) -} - -function Strategy() { - return ( -
- }> - - - - -
- ) -} - -export default Strategy diff --git a/packages/app/src/routes/Tokens.tsx b/packages/app/src/routes/Tokens.tsx deleted file mode 100644 index 43ff367..0000000 --- a/packages/app/src/routes/Tokens.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Suspense, useCallback, useEffect, useMemo, useState } from 'react' -import InfiniteScroll from 'react-infinite-scroll-component' -import type { StrategyMetadata } from '../../schemas/StrategyMetadata' -import BackItUp from '../components/BackItUp' -import Skeleton from '../components/eg/Skeleton' -import TokenIcon from '../components/eg/TokenIcon' -import Link from '../components/elements/Link' -import { useFinder } from '../components/Finder' -import { useStrategyMeta } from '../hooks/useStrategyMeta' -import { useToggleChainStore } from '../hooks/useToggleChainStore' - -const INFINTE_SCROLL_FRAME_SIZE = 20 - -function List() { - const { finderString } = useFinder() - const { toggledChains } = useToggleChainStore() - const { strategies } = useStrategyMeta() - - const filter: StrategyMetadata[] = useMemo(() => { - return strategies.filter( - (strategy: StrategyMetadata) => - toggledChains.has(strategy.chainId) && - (strategy.name.toLowerCase().includes(finderString.toLowerCase()) || - strategy.address.toLowerCase().includes(finderString.toLowerCase())), - ) - }, [strategies, finderString, toggledChains]) - - const [items, setItems] = useState(filter?.slice(0, INFINTE_SCROLL_FRAME_SIZE)) - useEffect(() => setItems(filter?.slice(0, INFINTE_SCROLL_FRAME_SIZE)), [filter]) - const hasMoreFrames = useMemo(() => items.length < filter.length, [items, filter]) - const fetchFrame = useCallback(() => { - setItems((prevItems) => [ - ...prevItems, - ...filter.slice(prevItems.length, prevItems.length + INFINTE_SCROLL_FRAME_SIZE), - ]) - }, [filter]) - - return ( - - {items.map((strategy: StrategyMetadata) => ( - - -
- {strategy.address.slice(0, 6)}..{strategy.address.slice(-6)} -
-
{strategy.name || 'No name onchain'}
- - ))} -
- ) -} - -function StrategiesSkeleton() { - return ( -
- - - - - - - - - -
- ) -} - -function Tokens() { - return ( -
- }> - - - -
- ) -} - -export default Tokens diff --git a/packages/app/src/routes/Vault.tsx b/packages/app/src/routes/Vault.tsx deleted file mode 100644 index d566ca5..0000000 --- a/packages/app/src/routes/Vault.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { useMutation } from '@tanstack/react-query' -import { Suspense } from 'react' -import { PiGitPullRequest } from 'react-icons/pi' -import { useParams } from 'react-router-dom' -import { chains } from '../../lib/chains' -import { type VaultMetadata, VaultMetadataSchema } from '../../schemas/VaultMetadata' -import Button from '../components/eg/elements/Button' -import Skeleton from '../components/eg/Skeleton' -import GithubSignIn, { useGithubUser } from '../components/GithubSignIn' -import MetaData, { MetaDataProvider, useMetaData } from '../components/SchemaForm' -import { useVaultsMeta } from '../hooks/useVaultMeta' - -function PullRequestButton() { - const { o: vault, isDirty, formState } = useMetaData() - const { rawJsonChainMap } = useVaultsMeta() - - const createPullRequest = useMutation({ - mutationFn: async () => { - const original = rawJsonChainMap[vault.chainId] - const path = `packages/cdn/vaults/${vault.chainId}.json` - - // Find and replace the specific vault - const updatedArray = original.map((vaultObj: VaultMetadata) => - vaultObj.address.toLowerCase() === vault.address.toLowerCase() ? formState : vaultObj, - ) - - const response = await fetch('/api/pr', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - token: sessionStorage.getItem('github_token'), - path, - contents: JSON.stringify(updatedArray, null, 2), - }), - }) - - const result = await response.json() - - if (!result.success) { - throw new Error(result.error || 'Failed to create pull request') - } - - return result - }, - onSuccess: (data) => { - window.open(data.pullRequestUrl, '_blank') - }, - onError: (error) => { - console.error('PR creation failed:', error) - alert(`Failed to create pull request: ${error.message}`) - }, - }) - - // Throw a promise to trigger Suspense when pending - if (createPullRequest.isPending) { - throw new Promise(() => {}) // This will never resolve, keeping Suspense active - } - - return ( - - ) -} - -function VaultDetails() { - const { signedIn } = useGithubUser() - const { o: vault } = useMetaData() - return ( -
-
-

{vault.name}

-
- chain: {chains[vault.chainId]?.name} ({vault.chainId}) -
-
address: {vault.address}
-
registry: {vault.registry}
-
- - }> - {signedIn && } - {!signedIn && } - -
- ) -} - -function Provider({ children }: { children: React.ReactNode }) { - const { chainId, address } = useParams() - const { vaults } = useVaultsMeta() - - const vault = vaults.find( - (v) => v.chainId.toString() === chainId && v.address.toLowerCase() === address?.toLowerCase(), - ) - - if (!vault) { - throw new Error('Vault not found') - } - - return ( - - {children} - - ) -} - -function VaultSkeleton() { - return ( -
- - - - - -
- ) -} - -function Vault() { - return ( -
- }> - - - - -
- ) -} - -export default Vault diff --git a/packages/app/src/routes/Vaults.tsx b/packages/app/src/routes/Vaults.tsx deleted file mode 100644 index a7784a4..0000000 --- a/packages/app/src/routes/Vaults.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { Suspense, useCallback, useEffect, useMemo, useState } from 'react' -import InfiniteScroll from 'react-infinite-scroll-component' -import type { VaultMetadata } from '../../schemas/VaultMetadata' -import BackItUp from '../components/BackItUp' -import Skeleton from '../components/eg/Skeleton' -import TokenIcon from '../components/eg/TokenIcon' -import Link from '../components/elements/Link' -import { useFinder } from '../components/Finder' -import { useToggleChainStore } from '../hooks/useToggleChainStore' -import { useVaultsMeta } from '../hooks/useVaultMeta' - -const INFINTE_SCROLL_FRAME_SIZE = 20 - -function List() { - const { finderString } = useFinder() - const { toggledChains } = useToggleChainStore() - const { vaults } = useVaultsMeta() - - const filter: VaultMetadata[] = useMemo(() => { - return vaults.filter( - (vault: VaultMetadata) => - toggledChains.has(vault.chainId) && - (vault.name.toLowerCase().includes(finderString.toLowerCase()) || - vault.address.toLowerCase().includes(finderString.toLowerCase())), - ) - }, [vaults, finderString, toggledChains]) - - const [items, setItems] = useState(filter?.slice(0, INFINTE_SCROLL_FRAME_SIZE)) - useEffect(() => setItems(filter?.slice(0, INFINTE_SCROLL_FRAME_SIZE)), [filter]) - const hasMoreFrames = useMemo(() => items.length < filter.length, [items, filter]) - const fetchFrame = useCallback(() => { - setItems((prevItems) => [ - ...prevItems, - ...filter.slice(prevItems.length, prevItems.length + INFINTE_SCROLL_FRAME_SIZE), - ]) - }, [filter]) - - return ( - - {items.map((vault: VaultMetadata) => ( - - -
- {vault.address.slice(0, 6)}..{vault.address.slice(-6)} -
-
{vault.name}
- - ))} -
- ) -} - -function VaultsSkeleton() { - return ( -
- - - - - - - - - -
- ) -} - -function Vaults() { - return ( -
- }> - - - -
- ) -} - -export default Vaults diff --git a/packages/cdn/strategies/1.json b/packages/cdn/strategies/1.json index 1cd7722..6996eeb 100644 --- a/packages/cdn/strategies/1.json +++ b/packages/cdn/strategies/1.json @@ -989,7 +989,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Morpho" + ], + "githubCode": "https://github.com/Schlagonia/Generic4626/blob/morpho/src/Strategies/Morpho/Mainnet/MorphoCompounder.sol", + "strategyType": "Compounder" }, { "chainId": 1, @@ -17414,7 +17418,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/Schlagonia/depositors/blob/susdc/src/USDCToUSDS.sol", + "strategyType": "Depositor" }, { "chainId": 1, @@ -17450,7 +17456,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/Schlagonia/tokenized-looper/blob/master/src/morpho/InfinifiMorphoLooper.sol", + "strategyType": "Looper" }, { "chainId": 1, @@ -17657,7 +17665,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Pendle" + ], + "githubCode": "https://github.com/johnnyonline/yv3-pendle-PT-strategy/blob/buy-pt/src/Strategy.sol", + "strategyType": "" }, { "chainId": 1, @@ -17936,7 +17948,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/Schlagonia/tokenized-looper/blob/aave/src/morpho/SyrupMorphoLooper.sol", + "strategyType": "Looper" }, { "chainId": 1, @@ -17945,7 +17959,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/Schlagonia/tokenized-cctp/blob/master/src/CCTPStrategy.sol", + "strategyType": "CCTP" }, { "chainId": 1, @@ -17954,7 +17970,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/Schlagonia/depositors/pull/2", + "strategyType": "Depositor" }, { "chainId": 1, @@ -18044,7 +18062,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Aave" + ], + "githubCode": "https://github.com/johnnyonline/yv3-aave-lender-borrower-strategy/blob/master/src/Strategy.sol", + "strategyType": "Lender-Borrower" }, { "chainId": 1, @@ -18053,7 +18075,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Aave" + ], + "githubCode": "https://github.com/johnnyonline/yv3-aave-lender-borrower-strategy/blob/master/src/Strategy.sol", + "strategyType": "Lender-Borrower" }, { "chainId": 1, @@ -18062,7 +18088,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Morpho" + ], + "githubCode": "https://github.com/Schlagonia/lender-borrower/blob/morpho/src/MorphoBlueLenderBorrower.sol", + "strategyType": "Lender-Borrower" }, { "chainId": 1, @@ -18071,7 +18101,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Aave" + ], + "githubCode": "https://github.com/johnnyonline/yv3-aave-lender-borrower-strategy/blob/master/src/Strategy.sol", + "strategyType": "Lender-Borrower" }, { "chainId": 1, @@ -18080,7 +18114,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Aave" + ], + "githubCode": "https://github.com/johnnyonline/yv3-aave-lender-borrower-strategy/blob/master/src/Strategy.sol", + "strategyType": "Lender-Borrower" }, { "chainId": 1, @@ -18089,7 +18127,11 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [ + "Morpho" + ], + "githubCode": "https://github.com/Schlagonia/lender-borrower/blob/morpho/src/MorphoBlueLenderBorrower.sol", + "strategyType": "Lender-Borrower" }, { "chainId": 1, @@ -18143,7 +18185,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/fp-crypto/susd3-strategy/blob/master/src/Strategy.sol", + "strategyType": "Compounder" }, { "chainId": 1, @@ -18161,7 +18205,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/Schlagonia/tokenized-cctp/blob/master/src/KatanaStrategy.sol", + "strategyType": "CCTP" }, { "chainId": 1, @@ -18170,7 +18216,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/Bases/convertors/BaseConvertor.sol", + "strategyType": "Convertor" }, { "chainId": 1, @@ -18188,7 +18236,9 @@ "isRetired": false, "displayName": "", "description": "", - "protocols": [] + "protocols": [], + "githubCode": "https://github.com/yearn/tokenized-strategy-periphery/blob/master/src/Bases/convertors/BaseConvertor.sol", + "strategyType": "Convertor" }, { "chainId": 1,