diff --git a/apps/common/components/ImageWithFallback.tsx b/apps/common/components/ImageWithFallback.tsx index 6dd92a4a0..116e82896 100755 --- a/apps/common/components/ImageWithFallback.tsx +++ b/apps/common/components/ImageWithFallback.tsx @@ -1,22 +1,17 @@ import React, {useState} from 'react'; import Image from 'next/image'; -import {cl} from '@builtbymom/web3/utils'; import {useUpdateEffect} from '@react-hookz/web'; import type {ImageProps} from 'next/image'; import type {CSSProperties, ReactElement} from 'react'; -type TImageWithFallback = ImageProps & { - smWidth?: number; - smHeight?: number; -}; -export function ImageWithFallback(props: TImageWithFallback): ReactElement { - const {alt, src, smWidth, smHeight, ...rest} = props; - const [imageSrc, set_imageSrc] = useState(`${src}?fallback=true`); +function ImageWithFallback(props: ImageProps & {altSrc?: string}): ReactElement { + const {alt, src, altSrc, ...rest} = props; + const [imageSrc, set_imageSrc] = useState(altSrc ? src : `${src}?fallback=true`); const [imageStyle, set_imageStyle] = useState({}); useUpdateEffect((): void => { - set_imageSrc(`${src}?fallback=true`); + set_imageSrc(altSrc ? src : `${src}?fallback=true`); set_imageStyle({}); }, [src]); @@ -24,14 +19,21 @@ export function ImageWithFallback(props: TImageWithFallback): ReactElement { {alt} { + if (altSrc && imageSrc !== `${altSrc}?fallback=true`) { + console.warn('using placeholder'); + set_imageSrc(`${altSrc}?fallback=true`); + return; + } set_imageSrc('/placeholder.png'); set_imageStyle({filter: 'opacity(0.2)'}); }} @@ -39,3 +41,5 @@ export function ImageWithFallback(props: TImageWithFallback): ReactElement { /> ); } + +export {ImageWithFallback}; diff --git a/apps/common/hooks/useFetchYearnVaults.ts b/apps/common/hooks/useFetchYearnVaults.ts index 71dea6da8..ef96f1066 100644 --- a/apps/common/hooks/useFetchYearnVaults.ts +++ b/apps/common/hooks/useFetchYearnVaults.ts @@ -9,122 +9,160 @@ import type {KeyedMutator} from 'swr'; import type {TYDaemonVault, TYDaemonVaults} from '@yearn-finance/web-lib/utils/schemas/yDaemonVaultsSchemas'; import type {TDict} from '@builtbymom/web3/types'; -/****************************************************************************** - ** The useFetchYearnVaults hook is used to fetch the vaults from the yDaemon - ** API. - ** It will fetch 3 kinds of vaults: - ** - The active vaults - ** - The vaults that are in the migration process - ** - The retired vaults - *****************************************************************************/ -function useFetchYearnVaults(chainIDs?: number[] | undefined): { +/************************************************************************************************ + ** Constants and Types for the useFetchYearnVaults hook + ** These values are used to configure the pagination and API requests + ************************************************************************************************/ +const ITEMS_PER_PAGE = 200; +const DEFAULT_CHAIN_IDS = [1, 10, 137, 250, 8453, 42161]; + +type TUseFetchYearnVaultsProps = { + chainIDs?: number[]; + shouldFetchMigrations?: boolean; + shouldFetchRetired?: boolean; +}; + +type TUseFetchYearnVaultsReturn = { vaults: TDict; vaultsMigrations: TDict; vaultsRetired: TDict; isLoading: boolean; + error: Error | null; mutate: KeyedMutator; -} { - const {yDaemonBaseUri: yDaemonBaseUriWithoutChain} = useYDaemonBaseURI(); +}; + +/************************************************************************************************ + ** Helper function to create the URL parameters for the vaults API request + ** This ensures consistency in how we build our API URLs + ************************************************************************************************/ +function getVaultsURLParams({chainIDs, page, limit}: {chainIDs: number[]; page: number; limit: number}): string { + return new URLSearchParams({ + hideAlways: 'true', + orderBy: 'featuringScore', + orderDirection: 'desc', + strategiesDetails: 'withDetails', + strategiesCondition: 'inQueue', + chainIDs: chainIDs.join(','), + limit: limit.toString(), + page: page.toString() + }).toString(); +} + +/************************************************************************************************ + ** The useFetchYearnVaults hook fetches vault data from the yDaemon API + ** It handles pagination and provides access to active, migrating, and retired vaults + ** The hook now includes proper error handling and optional fetching of migrations/retired vaults + ************************************************************************************************/ +function useFetchYearnVaults({ + chainIDs = DEFAULT_CHAIN_IDS, + shouldFetchMigrations = true, + shouldFetchRetired = true +}: TUseFetchYearnVaultsProps = {}): TUseFetchYearnVaultsReturn { + const {yDaemonBaseUri: baseUri} = useYDaemonBaseURI(); const [allVaults, set_allVaults] = useState([]); const [currentPage, set_currentPage] = useState(1); - const limit = 200; + const [error, set_error] = useState(null); + const [isLoadingMore, set_isLoadingMore] = useState(false); + // Fetch active vaults with pagination const { - data: vaults, - isLoading, - mutate + data: currentPageVaults, + isLoading: isLoadingCurrentPage, + mutate, + error: currentPageError } = useFetch({ - endpoint: `${yDaemonBaseUriWithoutChain}/vaults?${new URLSearchParams({ - hideAlways: 'true', - orderBy: 'featuringScore', - orderDirection: 'desc', - strategiesDetails: 'withDetails', - strategiesCondition: 'inQueue', - chainIDs: chainIDs ? chainIDs.join(',') : [1, 10, 137, 250, 8453, 42161].join(','), - limit: limit.toString(), - page: currentPage.toString() + endpoint: `${baseUri}/vaults?${getVaultsURLParams({ + chainIDs, + page: currentPage, + limit: ITEMS_PER_PAGE })}`, schema: yDaemonVaultsSchema }); + // Handle pagination and vault accumulation useEffect(() => { - let hasMore = true; - if (vaults) { - if (vaults.length < limit) { - hasMore = false; - } - set_allVaults(prev => [...prev, ...vaults]); - if (hasMore) { - set_currentPage(prev => prev + 1); - } + if (currentPageError) { + set_error(currentPageError); + return; } - }, [vaults]); - // const vaultsMigrations: TYDaemonVaults = useMemo(() => [], []); + if (!currentPageVaults || isLoadingMore) { + return; + } + + set_isLoadingMore(true); + set_allVaults(prev => [...prev, ...currentPageVaults]); + + const hasMore = currentPageVaults.length === ITEMS_PER_PAGE; + if (hasMore) { + set_currentPage(prev => prev + 1); + } + set_isLoadingMore(false); + }, [currentPageVaults, currentPageError, isLoadingMore]); + + // Fetch migration vaults if enabled const {data: vaultsMigrations} = useFetch({ - endpoint: `${yDaemonBaseUriWithoutChain}/vaults?${new URLSearchParams({ - chainIDs: chainIDs ? chainIDs.join(',') : [1, 10, 137, 250, 8453, 42161].join(','), - migratable: 'nodust' - })}`, + endpoint: shouldFetchMigrations + ? `${baseUri}/vaults?${new URLSearchParams({ + chainIDs: chainIDs.join(','), + migratable: 'nodust' + })}` + : null, schema: yDaemonVaultsSchema }); - // const vaultsRetired: TYDaemonVaults = useMemo(() => [], []); + // Fetch retired vaults if enabled const {data: vaultsRetired} = useFetch({ - endpoint: `${yDaemonBaseUriWithoutChain}/vaults/retired`, + endpoint: shouldFetchRetired ? `${baseUri}/vaults/retired` : null, schema: yDaemonVaultsSchema }); + // Process active vaults into dictionary const vaultsObject = useDeepCompareMemo((): TDict => { - if (!allVaults) { + if (!allVaults?.length) { return {}; } - const _vaultsObject = (allVaults || []).reduce((acc: TDict, vault): TDict => { + return allVaults.reduce((acc: TDict, vault): TDict => { if (!vault.migration.available) { acc[toAddress(vault.address)] = vault; } return acc; }, {}); - return _vaultsObject; }, [allVaults]); + // Process migration vaults into dictionary const vaultsMigrationsObject = useDeepCompareMemo((): TDict => { - if (!vaultsMigrations) { + if (!vaultsMigrations?.length) { return {}; } - const _migratableVaultsObject = (vaultsMigrations || []).reduce( - (acc: TDict, vault): TDict => { - if (toAddress(vault.address) !== toAddress(vault.migration.address)) { - acc[toAddress(vault.address)] = vault; - } - return acc; - }, - {} - ); - return _migratableVaultsObject; + return vaultsMigrations.reduce((acc: TDict, vault): TDict => { + if (toAddress(vault.address) !== toAddress(vault.migration.address)) { + acc[toAddress(vault.address)] = vault; + } + return acc; + }, {}); }, [vaultsMigrations]); + // Process retired vaults into dictionary const vaultsRetiredObject = useDeepCompareMemo((): TDict => { - if (!vaultsRetired) { + if (!vaultsRetired?.length) { return {}; } - const _retiredVaultsObject = (vaultsRetired || []).reduce( - (acc: TDict, vault): TDict => { - acc[toAddress(vault.address)] = vault; - return acc; - }, - {} - ); - return _retiredVaultsObject; + return vaultsRetired.reduce((acc: TDict, vault): TDict => { + acc[toAddress(vault.address)] = vault; + return acc; + }, {}); }, [vaultsRetired]); return { vaults: vaultsObject, vaultsMigrations: vaultsMigrationsObject, vaultsRetired: vaultsRetiredObject, - isLoading, + isLoading: isLoadingCurrentPage || isLoadingMore, + error, mutate }; } export {useFetchYearnVaults}; +export type {TUseFetchYearnVaultsProps, TUseFetchYearnVaultsReturn}; diff --git a/bun.lockb b/bun.lockb index 57ae28754..48ba0101c 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/next.config.js b/next.config.js index 7757019f5..7de872b86 100755 --- a/next.config.js +++ b/next.config.js @@ -1,195 +1,193 @@ // eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars const {withPlausibleProxy} = require('next-plausible'); /* eslint-disable @typescript-eslint/explicit-function-return-type */ -const withPWA = require('next-pwa')({ - dest: 'public', - disable: process.env.NODE_ENV !== 'production' -}); +// const withPWA = require('next-pwa')({ +// dest: 'public', +// disable: process.env.NODE_ENV !== 'production' +// }); module.exports = withPlausibleProxy({ scriptName: 'script', customDomain: 'https://yearn.fi' -})( - withPWA({ - images: { - remotePatterns: [ - { - protocol: 'https', - hostname: 'rawcdn.githack.com' - }, - { - protocol: 'https', - hostname: 'raw.githubusercontent.com' - }, - { - protocol: 'https', - hostname: 'assets.smold.app' - }, - { - protocol: 'https', - hostname: '**.yearn.fi' - } - ] - }, - async rewrites() { - return [ - { - source: '/js/script.js', - destination: 'https://plausible.io/js/script.js' - }, - { - source: '/api/event', - destination: 'https://plausible.io/api/event' - } - ]; - }, - redirects() { - return [ - { - source: '/ybribe/:path*', - destination: 'https://ybribe.yearn.fi/:path*', - permanent: true - }, - { - source: '/ycrv/:path*', - destination: 'https://ycrv.yearn.fi/:path*', - permanent: true - }, - { - source: '/veyfi/:path*', - destination: 'https://veyfi.yearn.fi/:path*', - permanent: true - }, - { - source: '/vaults/factory/:path*', - destination: 'https://factory.yearn.fi/:path*', - permanent: true - }, - { - source: '/:path*', - has: [{type: 'host', value: 'vote.yearn.fi'}], - destination: 'https://yearn.fi/veyfi/:path*', - permanent: true - }, - // - { - source: '/twitter', - destination: 'https://twitter.com/yearnfi', - permanent: true - }, - { - source: '/telegram', - destination: 'https://t.me/yearnfinance/', - permanent: true - }, - { - source: '/medium', - destination: 'https://medium.com/iearn', - permanent: true - }, - { - source: '/governance', - destination: 'https://gov.yearn.fi/', - permanent: true - }, - { - source: '/snapshot', - destination: 'https://snapshot.org/#/veyfi.eth', - permanent: true - }, - { - source: '/github', - destination: 'https://github.com/yearn/yearn.fi', - permanent: true - }, - { - source: '/static/tokenlist.json', - destination: 'https://raw.githubusercontent.com/SmolDapp/tokenLists/main/lists/yearn.json', - permanent: true - } - ]; - }, - env: { - /* 🔵 - Yearn Finance ************************************************** - ** Config over the RPC - **********************************************************************/ - RPC_URI_FOR: { - /********************************************************************************** - ** New RPC Setup for mainnet networks - *********************************************************************************/ - 1: process.env.RPC_URI_FOR_1, - 10: process.env.RPC_URI_FOR_10, - 56: process.env.RPC_URI_FOR_56, - 100: process.env.RPC_URI_FOR_100, - 137: process.env.RPC_URI_FOR_137, - 250: process.env.RPC_URI_FOR_250, - 252: process.env.RPC_URI_FOR_252, - 288: process.env.RPC_URI_FOR_288, - 8453: process.env.RPC_URI_FOR_8453, - 42161: process.env.RPC_URI_FOR_42161, - 42170: process.env.RPC_URI_FOR_42170, - 56288: process.env.RPC_URI_FOR_56288, - 81457: process.env.RPC_URI_FOR_81457, - 111188: process.env.RPC_URI_FOR_111188, - - /********************************************************************************** - ** New RPC Setup for testnet networks - *********************************************************************************/ - 97: process.env.RPC_URL_BINANCE_TESTNET, - 400: process.env.RPC_URL_OPTIMISM_GOERLI, - 2522: process.env.RPC_URI_FOR_2522, - 9728: process.env.RPC_URI_FOR_9728, - 17000: process.env.RPC_URI_FOR_17000, - 18233: process.env.RPC_URI_FOR_18233, - 28882: process.env.RPC_URI_FOR_28882, - 80001: process.env.RPC_URI_FOR_80001, - 84532: process.env.RPC_URI_FOR_84532, - 421614: process.env.RPC_URI_FOR_421614, - 11155111: process.env.RPC_URI_FOR_11155111, - 11155420: process.env.RPC_URI_FOR_11155420 +})({ + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'rawcdn.githack.com' + }, + { + protocol: 'https', + hostname: 'raw.githubusercontent.com' + }, + { + protocol: 'https', + hostname: 'assets.smold.app' + }, + { + protocol: 'https', + hostname: '**.yearn.fi' + } + ] + }, + async rewrites() { + return [ + { + source: '/js/script.js', + destination: 'https://plausible.io/js/script.js' + }, + { + source: '/api/event', + destination: 'https://plausible.io/api/event' + } + ]; + }, + redirects() { + return [ + { + source: '/ybribe/:path*', + destination: 'https://ybribe.yearn.fi/:path*', + permanent: true + }, + { + source: '/ycrv/:path*', + destination: 'https://ycrv.yearn.fi/:path*', + permanent: true + }, + { + source: '/veyfi/:path*', + destination: 'https://veyfi.yearn.fi/:path*', + permanent: true + }, + { + source: '/vaults/factory/:path*', + destination: 'https://factory.yearn.fi/:path*', + permanent: true + }, + { + source: '/:path*', + has: [{type: 'host', value: 'vote.yearn.fi'}], + destination: 'https://yearn.fi/veyfi/:path*', + permanent: true }, + // + { + source: '/twitter', + destination: 'https://twitter.com/yearnfi', + permanent: true + }, + { + source: '/telegram', + destination: 'https://t.me/yearnfinance/', + permanent: true + }, + { + source: '/medium', + destination: 'https://medium.com/iearn', + permanent: true + }, + { + source: '/governance', + destination: 'https://gov.yearn.fi/', + permanent: true + }, + { + source: '/snapshot', + destination: 'https://snapshot.org/#/veyfi.eth', + permanent: true + }, + { + source: '/github', + destination: 'https://github.com/yearn/yearn.fi', + permanent: true + }, + { + source: '/static/tokenlist.json', + destination: 'https://raw.githubusercontent.com/SmolDapp/tokenLists/main/lists/yearn.json', + permanent: true + } + ]; + }, + env: { + /* 🔵 - Yearn Finance ************************************************** + ** Config over the RPC + **********************************************************************/ + RPC_URI_FOR: { /********************************************************************************** - ** Legacy RPC configuration, mainnet and testnet + ** New RPC Setup for mainnet networks *********************************************************************************/ - JSON_RPC_URL: { - 1: process.env.RPC_URI_FOR_1, - 10: process.env.RPC_URI_FOR_10, - 56: process.env.RPC_URI_FOR_56, - 97: process.env.RPC_URL_FOR_97, - 137: process.env.RPC_URL_FOR_137, - 250: process.env.RPC_URL_FOR_250, - 420: process.env.RPC_URL_FOR_420, - 8453: process.env.RPC_URL_FOR_8453, - 80001: process.env.RPC_URL_FOR_80001, - 42161: process.env.RPC_URL_FOR_42161, - 11155111: process.env.RPC_URL_FOR_11155111 - }, - RPC_URI_FOR_1: process.env.RPC_URI_FOR_1, - RPC_URI_FOR_10: process.env.RPC_URI_FOR_10, - RPC_URI_FOR_137: process.env.RPC_URI_FOR_137, - RPC_URI_FOR_252: process.env.RPC_URI_FOR_252, - RPC_URI_FOR_288: process.env.RPC_URI_FOR_288, - RPC_URI_FOR_8453: process.env.RPC_URI_FOR_8453, - RPC_URI_FOR_42161: process.env.RPC_URI_FOR_42161, - RPC_URI_FOR_42170: process.env.RPC_URI_FOR_42170, - RPC_URI_FOR_56288: process.env.RPC_URI_FOR_56288, - RPC_URI_FOR_81457: process.env.RPC_URI_FOR_81457, - RPC_URI_FOR_111188: process.env.RPC_URI_FOR_111188, + 1: process.env.RPC_URI_FOR_1, + 10: process.env.RPC_URI_FOR_10, + 56: process.env.RPC_URI_FOR_56, + 100: process.env.RPC_URI_FOR_100, + 137: process.env.RPC_URI_FOR_137, + 250: process.env.RPC_URI_FOR_250, + 252: process.env.RPC_URI_FOR_252, + 288: process.env.RPC_URI_FOR_288, + 8453: process.env.RPC_URI_FOR_8453, + 42161: process.env.RPC_URI_FOR_42161, + 42170: process.env.RPC_URI_FOR_42170, + 56288: process.env.RPC_URI_FOR_56288, + 81457: process.env.RPC_URI_FOR_81457, + 111188: process.env.RPC_URI_FOR_111188, - ALCHEMY_KEY: process.env.ALCHEMY_KEY, - ALCHEMY_API_KEY: process.env.ALCHEMY_API_KEY, - INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, - WALLETCONNECT_PROJECT_ID: process.env.WALLETCONNECT_PROJECT_ID, + /********************************************************************************** + ** New RPC Setup for testnet networks + *********************************************************************************/ + 97: process.env.RPC_URL_BINANCE_TESTNET, + 400: process.env.RPC_URL_OPTIMISM_GOERLI, + 2522: process.env.RPC_URI_FOR_2522, + 9728: process.env.RPC_URI_FOR_9728, + 17000: process.env.RPC_URI_FOR_17000, + 18233: process.env.RPC_URI_FOR_18233, + 28882: process.env.RPC_URI_FOR_28882, + 80001: process.env.RPC_URI_FOR_80001, + 84532: process.env.RPC_URI_FOR_84532, + 421614: process.env.RPC_URI_FOR_421614, + 11155111: process.env.RPC_URI_FOR_11155111, + 11155420: process.env.RPC_URI_FOR_11155420 + }, + /********************************************************************************** + ** Legacy RPC configuration, mainnet and testnet + *********************************************************************************/ + JSON_RPC_URL: { + 1: process.env.RPC_URI_FOR_1, + 10: process.env.RPC_URI_FOR_10, + 56: process.env.RPC_URI_FOR_56, + 97: process.env.RPC_URL_FOR_97, + 137: process.env.RPC_URL_FOR_137, + 250: process.env.RPC_URL_FOR_250, + 420: process.env.RPC_URL_FOR_420, + 8453: process.env.RPC_URL_FOR_8453, + 80001: process.env.RPC_URL_FOR_80001, + 42161: process.env.RPC_URL_FOR_42161, + 11155111: process.env.RPC_URL_FOR_11155111 + }, + RPC_URI_FOR_1: process.env.RPC_URI_FOR_1, + RPC_URI_FOR_10: process.env.RPC_URI_FOR_10, + RPC_URI_FOR_137: process.env.RPC_URI_FOR_137, + RPC_URI_FOR_252: process.env.RPC_URI_FOR_252, + RPC_URI_FOR_288: process.env.RPC_URI_FOR_288, + RPC_URI_FOR_8453: process.env.RPC_URI_FOR_8453, + RPC_URI_FOR_42161: process.env.RPC_URI_FOR_42161, + RPC_URI_FOR_42170: process.env.RPC_URI_FOR_42170, + RPC_URI_FOR_56288: process.env.RPC_URI_FOR_56288, + RPC_URI_FOR_81457: process.env.RPC_URI_FOR_81457, + RPC_URI_FOR_111188: process.env.RPC_URI_FOR_111188, + + ALCHEMY_KEY: process.env.ALCHEMY_KEY, + ALCHEMY_API_KEY: process.env.ALCHEMY_API_KEY, + INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, + WALLETCONNECT_PROJECT_ID: process.env.WALLETCONNECT_PROJECT_ID, - PARTNER_ID_ADDRESS: '0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52', - SHOULD_USE_PARTNER_CONTRACT: true, - RANGE_LIMIT: 1_000_000, + PARTNER_ID_ADDRESS: '0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52', + SHOULD_USE_PARTNER_CONTRACT: true, + RANGE_LIMIT: 1_000_000, - YDAEMON_BASE_URI: process.env.YDAEMON_BASE_URI, - // YDAEMON_BASE_URI: 'http://localhost:8080', - BASE_YEARN_ASSETS_URI: 'https://assets.smold.app/api/token', - BASE_YEARN_CHAIN_URI: 'https://assets.smold.app/api/chain', - SMOL_ASSETS_URL: 'https://assets.smold.app/api' - } - }) -); + YDAEMON_BASE_URI: process.env.YDAEMON_BASE_URI, + // YDAEMON_BASE_URI: 'http://localhost:8080', + BASE_YEARN_ASSETS_URI: 'https://assets.smold.app/api/token', + BASE_YEARN_CHAIN_URI: 'https://assets.smold.app/api/chain', + SMOL_ASSETS_URL: 'https://assets.smold.app/api' + } +}); diff --git a/package.json b/package.json index b8691e364..ff5993f0e 100644 --- a/package.json +++ b/package.json @@ -1,87 +1,87 @@ { - "name": "yearnfi", - "version": "0.3.7", - "scripts": { - "dev": "next", - "inspect": "NODE_OPTIONS='--inspect' next", - "dev:ts": "tsc --watch", - "start": "tsc && next build && next start", - "build": "tsc && next build", - "export": "tsc && next build && next export -o ipfs", - "lint": "eslint . --ext .js,.jsx,.ts,.tsx", - "prettier": "prettier --check \"./**/**/*.{json,js,ts,tsx,scss}\"", - "prettier-format": "prettier --config .prettierrc \"./**/**/*.{json,js,ts,tsx,scss,md}\" --write", - "tslint": "tsc -p tsconfig.json --noEmit", - "bump": "bump", - "test": "vitest run" - }, - "dependencies": { - "@builtbymom/web3": "0.0.202", - "@cowprotocol/cow-sdk": "2.1.0", - "@headlessui/react": "^2.0.4", - "@rainbow-me/rainbowkit": "2.1.3", - "@tailwindcss/typography": "^0.5.13", - "@tanstack/react-query": "^5.51.11", - "@wagmi/core": "^2.11.7", - "@yearn-finance/web-lib": "^4.1.4", - "axios": "^1.7.2", - "ethers": "5.7.2", - "framer-motion": "^11.2.10", - "graphql": "^16.8.2", - "graphql-request": "^7.0.1", - "next": "^14.2.5", - "next-plausible": "^3.12.0", - "next-pwa": "^5.6.0", - "nprogress": "^0.2.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-paginate": "^8.2.0", - "recharts": "^2.12.7", - "swr": "^2.2.5", - "viem": "2.17.3", - "vite": "^5.2.13", - "wagmi": "2.10.10", - "xxhashjs": "^0.2.2", - "zod": "^3.23.8" - }, - "devDependencies": { - "@next/bundle-analyzer": "^14.2.4", - "@next/eslint-plugin-next": "^14.2.4", - "@testing-library/react": "^16.0.0", - "@types/node": "^20.14.2", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.13.0", - "@typescript-eslint/parser": "^7.13.0", - "@vitejs/plugin-react": "^4.3.1", - "autoprefixer": "^10.4.19", - "babel-loader": "^9.1.3", - "bump": "^0.2.5", - "eslint": "^8.57.0", - "eslint-config-next": "^14.2.4", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-brackets": "^0.1.3", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-react": "^7.34.2", - "eslint-plugin-react-hooks": "^4.6.2", - "eslint-plugin-simple-import-sort": "^12.1.0", - "eslint-plugin-tailwindcss": "^3.17.3", - "eslint-plugin-unused-imports": "^4.0.0", - "husky": "^9.0.11", - "lint-staged": "^15.2.7", - "next-transpile-modules": "^10.0.1", - "postcss": "^8.4.38", - "postcss-import": "^16.1.0", - "postcss-nesting": "^12.1.5", - "prettier": "^3.3.2", - "sass": "^1.77.5", - "stylelint": "^16.6.1", - "stylelint-config-standard": "^36.0.0", - "tailwindcss": "^3.4.4", - "ts-loader": "^9.5.1", - "typescript": "^5.5.3", - "vitest": "^1.6.0", - "webpack": "^5.92.1" - } + "name": "yearnfi", + "version": "0.3.7", + "scripts": { + "dev": "next", + "inspect": "NODE_OPTIONS='--inspect' next", + "dev:ts": "tsc --watch", + "start": "tsc && next build && next start", + "build": "tsc && next build", + "export": "tsc && next build && next export -o ipfs", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx", + "prettier": "prettier --check \"./**/**/*.{json,js,ts,tsx,scss}\"", + "prettier-format": "prettier --config .prettierrc \"./**/**/*.{json,js,ts,tsx,scss,md}\" --write", + "tslint": "tsc -p tsconfig.json --noEmit", + "bump": "bump", + "test": "vitest run" + }, + "dependencies": { + "@builtbymom/web3": "0.0.202", + "@cowprotocol/cow-sdk": "2.1.0", + "@headlessui/react": "^2.0.4", + "@rainbow-me/rainbowkit": "2.1.3", + "@tailwindcss/typography": "^0.5.13", + "@tanstack/react-query": "^5.51.11", + "@wagmi/core": "^2.11.7", + "@yearn-finance/web-lib": "^4.1.4", + "axios": "^1.7.2", + "ethers": "5.7.2", + "framer-motion": "^11.2.10", + "graphql": "^16.8.2", + "graphql-request": "^7.0.1", + "next": "^15.0.3", + "next-plausible": "^3.12.0", + "next-pwa": "^5.6.0", + "nprogress": "^0.2.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-paginate": "^8.2.0", + "recharts": "^2.12.7", + "swr": "^2.2.5", + "viem": "2.17.3", + "vite": "^5.2.13", + "wagmi": "2.10.10", + "xxhashjs": "^0.2.2", + "zod": "^3.23.8" + }, + "devDependencies": { + "@next/bundle-analyzer": "^14.2.4", + "@next/eslint-plugin-next": "^14.2.4", + "@testing-library/react": "^16.0.0", + "@types/node": "^20.14.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.19", + "babel-loader": "^9.1.3", + "bump": "^0.2.5", + "eslint": "^8.57.0", + "eslint-config-next": "^14.2.4", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-brackets": "^0.1.3", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-react": "^7.34.2", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-simple-import-sort": "^12.1.0", + "eslint-plugin-tailwindcss": "^3.17.3", + "eslint-plugin-unused-imports": "^4.0.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.7", + "next-transpile-modules": "^10.0.1", + "postcss": "^8.4.38", + "postcss-import": "^16.1.0", + "postcss-nesting": "^12.1.5", + "prettier": "^3.3.2", + "sass": "^1.77.5", + "stylelint": "^16.6.1", + "stylelint-config-standard": "^36.0.0", + "tailwindcss": "^3.4.4", + "ts-loader": "^9.5.1", + "typescript": "^5.5.3", + "vitest": "^1.6.0", + "webpack": "^5.92.1" + } }