diff --git a/eslint.config.mjs b/eslint.config.mjs index d91065c4..d3d1b421 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -47,7 +47,7 @@ export default tseslint.config( // Ensure Next.js link, image, and other best practices ...eslintPluginReactHooks.configs.recommended.rules, '@typescript-eslint/no-empty-interface': 'off', - '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/no-unused-vars': 'off', 'no-prototype-builtins': 'off', 'require-jsdoc': 'off', diff --git a/src/api/assets/getDexAssets.ts b/src/api/assets/getDexAssets.ts index 64b078ec..0be774ea 100644 --- a/src/api/assets/getDexAssets.ts +++ b/src/api/assets/getDexAssets.ts @@ -8,7 +8,7 @@ import { osmosisTokens } from 'data/assets/osmosis-tokens' export default async function getDexAssets(chainConfig: ChainConfig) { try { - let tokens: any[] + let tokens: AstroportAsset[] // Load essential static data based on chain ID switch (chainConfig.id) { diff --git a/src/app/api/og/perps/[market]/route.tsx b/src/app/api/og/perps/[market]/route.tsx index ac472753..ea9c57ba 100644 --- a/src/app/api/og/perps/[market]/route.tsx +++ b/src/app/api/og/perps/[market]/route.tsx @@ -4,12 +4,11 @@ import { neutronPerps } from '../../../../../data/assets/neutron-perps' // Use Node.js runtime to avoid disabling SSG for other pages export const runtime = 'nodejs' -export async function GET(request: Request, context: any) { +export async function GET(request: Request, context: { params: Promise<{ market: string }> }) { try { - const marketParam = context.params.market - const marketDenom = `perps/${decodeURIComponent( - Array.isArray(marketParam) ? marketParam[0] : marketParam, - )}` + const params = await context.params + const marketParam = params.market + const marketDenom = `perps/${decodeURIComponent(marketParam)}` // Find the market asset data const marketAsset = neutronPerps.find((asset) => asset.denom === marketDenom) @@ -75,8 +74,9 @@ export async function GET(request: Request, context: any) { height: 540, }, ) - } catch (e: any) { - console.log(`${e.message}`) + } catch (e: unknown) { + const message = e instanceof Error ? e.message : 'Unknown error' + console.log(message) return new Response(`Failed to generate the image`, { status: 500, }) diff --git a/src/components/common/Chart/PieChart/PieChartBody.tsx b/src/components/common/Chart/PieChart/PieChartBody.tsx index 0e3eb573..0d51068d 100644 --- a/src/components/common/Chart/PieChart/PieChartBody.tsx +++ b/src/components/common/Chart/PieChart/PieChartBody.tsx @@ -1,4 +1,4 @@ -import { Cell, Legend, Pie, PieChart, ResponsiveContainer } from 'recharts' +import { Cell, Legend, Pie, PieChart, PieLabelRenderProps, ResponsiveContainer } from 'recharts' interface PieChartData { name: string @@ -14,24 +14,34 @@ interface Props { const RADIAN = Math.PI / 180 -const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, percent }: any) => { - const radius = innerRadius + (outerRadius - innerRadius) * 0.5 - const x = cx + radius * Math.cos(-midAngle * RADIAN) - const y = cy + radius * Math.sin(-midAngle * RADIAN) +const renderCustomizedLabel = (props: PieLabelRenderProps) => { + const { cx, cy, midAngle, innerRadius, outerRadius, percent } = props - if (percent < 0.05) return null // Don't show label if slice is too small + // Type guards for numeric properties + const cxNum = typeof cx === 'number' ? cx : 0 + const cyNum = typeof cy === 'number' ? cy : 0 + const midAngleNum = typeof midAngle === 'number' ? midAngle : 0 + const innerRadiusNum = typeof innerRadius === 'number' ? innerRadius : 0 + const outerRadiusNum = typeof outerRadius === 'number' ? outerRadius : 0 + const percentNum = typeof percent === 'number' ? percent : 0 + + const radius = innerRadiusNum + (outerRadiusNum - innerRadiusNum) * 0.5 + const x = cxNum + radius * Math.cos(-midAngleNum * RADIAN) + const y = cyNum + radius * Math.sin(-midAngleNum * RADIAN) + + if (percentNum < 0.05) return null // Don't show label if slice is too small return ( cx ? 'start' : 'end'} + textAnchor={x > cxNum ? 'start' : 'end'} dominantBaseline='central' fontSize={12} fontWeight={600} > - {`${(percent * 100).toFixed(1)}%`} + {`${(percentNum * 100).toFixed(1)}%`} ) } diff --git a/src/components/common/Chart/common/Legend/ChartLegend.tsx b/src/components/common/Chart/common/Legend/ChartLegend.tsx index 25ef7af4..34874014 100644 --- a/src/components/common/Chart/common/Legend/ChartLegend.tsx +++ b/src/components/common/Chart/common/Legend/ChartLegend.tsx @@ -13,13 +13,13 @@ interface LegendEntry { legendType: string name: string dataKey: string - [key: string]: any + [key: string]: unknown } } interface Props { payload: LegendEntry[] - data?: any[] + data?: Record[] } export default function ChartLegend(props: Props) { diff --git a/src/components/common/Table/Row.tsx b/src/components/common/Table/Row.tsx index 2afe790c..2009f63f 100644 --- a/src/components/common/Table/Row.tsx +++ b/src/components/common/Table/Row.tsx @@ -32,14 +32,35 @@ function getBorderColor( return perpRow.tradeDirection === 'short' ? 'border-loss' : 'border-profit' } +// Type guards for row data +function hasName(row: unknown): row is { name: string } { + return typeof row === 'object' && row !== null && 'name' in row +} + +function hasIsWhitelisted(row: unknown): row is { isWhitelisted?: boolean } { + return typeof row === 'object' && row !== null +} + +function hasAssetDenom(row: unknown): row is { asset: { denom: string } } { + return ( + typeof row === 'object' && + row !== null && + 'asset' in row && + typeof row.asset === 'object' && + row.asset !== null && + 'denom' in row.asset + ) +} + export default function Row(props: Props) { const { renderExpanded, table, row, type, spacingClassName, isSelectable, isBalancesTable } = props const canExpand = !!renderExpanded - const name = (row.original as any).name ?? '' + const name = hasName(row.original) ? row.original.name : '' const isWhitelisted = - (row.original as any).isWhitelisted !== false && !name.includes('Perps USDC Vault') + (hasIsWhitelisted(row.original) ? row.original.isWhitelisted !== false : true) && + !name.includes('Perps USDC Vault') return ( <> @@ -65,8 +86,8 @@ export default function Row(props: Props) { !isExpanded && row.toggleExpanded() } - if (props.onClick) { - props.onClick((row.original as any).asset.denom) + if (props.onClick && hasAssetDenom(row.original)) { + props.onClick(row.original.asset.denom) } }} > @@ -83,7 +104,11 @@ export default function Row(props: Props) { 'border-l', type && type !== 'strategies' && - getBorderColor(type, cell.row.original as any, isWhitelisted), + getBorderColor( + type, + cell.row.original as AccountBalanceRow | AccountStrategyRow | AccountPerpRow, + isWhitelisted, + ), cell.column.columnDef.meta?.className, !isWhitelisted && isBalancesTable && 'opacity-60', !isWhitelisted && isBalancesTable && 'group-hover/assetRow:opacity-100', diff --git a/src/hooks/charts/useChartDataTransform.ts b/src/hooks/charts/useChartDataTransform.ts index 203658b2..9ecd9935 100644 --- a/src/hooks/charts/useChartDataTransform.ts +++ b/src/hooks/charts/useChartDataTransform.ts @@ -9,7 +9,7 @@ interface ChartTransformation { } export const useChartDataTransform = ( - data: PerpsGlobalData | PerpsMarketData | PerpsVaultApyData, + data: PerpsGlobalData | PerpsMarketData | PerpsVaultApyData | OverviewData | null | undefined, transformations: ChartTransformation[], ) => { return useMemo(() => { diff --git a/src/hooks/tokenomics/useOverviewChartData.ts b/src/hooks/tokenomics/useOverviewChartData.ts index 7568240a..27040789 100644 --- a/src/hooks/tokenomics/useOverviewChartData.ts +++ b/src/hooks/tokenomics/useOverviewChartData.ts @@ -1,7 +1,7 @@ import { OVERVIEW_CHART_TRANSFORMATIONS } from 'constants/chartData' import { useChartDataTransform } from 'hooks/charts/useChartDataTransform' -export const useOverviewChartData = (data: any) => { +export const useOverviewChartData = (data: OverviewData | null | undefined) => { const tvlData = useChartDataTransform(data, OVERVIEW_CHART_TRANSFORMATIONS.tvl) const supplyBorrowData = useChartDataTransform(data, OVERVIEW_CHART_TRANSFORMATIONS.supplyBorrow) diff --git a/src/store/index.ts b/src/store/index.ts index 67f4ffc2..45510473 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -4,7 +4,7 @@ import { devtools } from 'zustand/middleware' import createCommonSlice from 'store/slices/common' import createModalSlice from 'store/slices/modal' -const store = (set: StoreApi['setState'], get: StoreApi['getState']) => ({ +const store = (set: StoreApi['setState'], get: StoreApi['getState']): Store => ({ ...createCommonSlice(set, get), ...createModalSlice(set, get), }) diff --git a/src/store/slices/common.ts b/src/store/slices/common.ts index 056d89a8..8c2ac1d8 100644 --- a/src/store/slices/common.ts +++ b/src/store/slices/common.ts @@ -4,7 +4,7 @@ import { StoreApi } from 'zustand' export default function createCommonSlice( set: StoreApi['setState'], get: StoreApi['getState'], -) { +): CommonSlice { return { accounts: null, balances: [], diff --git a/src/store/slices/modal.ts b/src/store/slices/modal.ts index a8d0c63d..41be5c85 100644 --- a/src/store/slices/modal.ts +++ b/src/store/slices/modal.ts @@ -3,9 +3,9 @@ import { StoreApi } from 'zustand' export default function createModalSlice( set: StoreApi['setState'], get: StoreApi['getState'], -) { +): ModalSlice { return { - resetStettingsModal: false, + resetSettingsModal: false, settingsModal: false, } } diff --git a/src/types/app.d.ts b/src/types/app.d.ts index bbc486a3..e43c83d1 100644 --- a/src/types/app.d.ts +++ b/src/types/app.d.ts @@ -1073,8 +1073,11 @@ interface TransactionEventAttribute { type TransactionType = 'default' | 'oracle' | 'create' | 'burn' | 'unlock' | 'transaction' interface CommonSlice { + accounts?: Account[] | null address?: string chainConfig: ChainConfig + creditAccounts?: Account[] | null + hlsAccounts?: HLSAccountWithStrategy[] | null userDomain?: { domain: string domain_full: string @@ -1103,6 +1106,7 @@ interface FocusComponent { } interface ModalSlice { + resetSettingsModal: boolean settingsModal: boolean } @@ -1314,7 +1318,7 @@ interface AstroportAsset { chainId: string denom: string symbol: string - icon?: string + icon?: string | null description: string decimals: number } diff --git a/src/types/classes/BNCoin.ts b/src/types/classes/BNCoin.ts index 182bc1cd..75b4973a 100644 --- a/src/types/classes/BNCoin.ts +++ b/src/types/classes/BNCoin.ts @@ -38,7 +38,7 @@ export class BNCoin { } } - toSignedCoin(): any { + toSignedCoin(): { denom: string; size: string } { return { denom: this.denom, size: this.amount.integerValue().toString(), diff --git a/src/utils/array.ts b/src/utils/array.ts index e58f6468..caa4c5ea 100644 --- a/src/utils/array.ts +++ b/src/utils/array.ts @@ -1,7 +1,17 @@ -export const byDenom = (denom: string) => (entity: any) => entity.denom === denom -export const bySymbol = (symbol: string) => (entity: any) => entity.symbol === symbol -const byTokenDenom = (denom: string) => (entity: any) => entity.token.denom === denom +interface HasDenom { + denom: string +} + +interface HasSymbol { + symbol: string +} + +interface HasToken { + token: { denom: string } +} +export const byDenom = (denom: string) => (entity: HasDenom) => entity.denom === denom +export const bySymbol = (symbol: string) => (entity: HasSymbol) => entity.symbol === symbol function partition(arr: Array, predicate: (val: T) => boolean): [Array, Array] { const partitioned: [Array, Array] = [[], []] diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index e5ac431e..5093edde 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -18,7 +18,7 @@ function getApproximateHourlyInterest(amount: string, borrowRate: number) { .multipliedBy(amount) } -function asyncThrottle Promise>(func: F, wait?: number) { +function asyncThrottle Promise>(func: F, wait?: number) { const throttled = throttle((resolve, reject, args: Parameters) => { func(...args) .then(resolve) diff --git a/src/utils/middleware.ts b/src/utils/middleware.ts index 311bf930..90dee046 100644 --- a/src/utils/middleware.ts +++ b/src/utils/middleware.ts @@ -1,7 +1,7 @@ import { Middleware, SWRHook } from 'swr' export const debugSWR: Middleware = (useSWRNext: SWRHook) => (key, fetcher, config) => { - const extendedFetcher = async (...args: any[]) => { + const extendedFetcher = async (...args: unknown[]) => { const startTime = Date.now() const res = await fetcher!(...args) process.env.NODE_ENV !== 'production' && diff --git a/src/utils/resolvers.ts b/src/utils/resolvers.ts index c0448b08..1dc4b19a 100644 --- a/src/utils/resolvers.ts +++ b/src/utils/resolvers.ts @@ -104,53 +104,53 @@ function resolvePerpsPositions( type: 'market', denom: position.denom, baseDenom: position.base_denom, - amount: BN(position.size as any), // Amount is negative for SHORT positions - tradeDirection: BN(position.size as any).isNegative() ? 'short' : 'long', + amount: BN(position.size as unknown as string), // Amount is negative for SHORT positions + tradeDirection: BN(position.size as unknown as string).isNegative() ? 'short' : 'long', entryPrice: BN(position.entry_exec_price), currentPrice: BN(position.current_exec_price), pnl: { net: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.unrealized_pnl.pnl as any) + BN(position.unrealized_pnl.pnl as unknown as string) .div(basePrice) - .plus(position.realized_pnl.pnl as any), + .plus(position.realized_pnl.pnl as unknown as string), ), realized: { net: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.realized_pnl.pnl as any), + BN(position.realized_pnl.pnl as unknown as string), ), price: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.realized_pnl.price_pnl as any), + BN(position.realized_pnl.price_pnl as unknown as string), ), funding: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.realized_pnl.accrued_funding as any), + BN(position.realized_pnl.accrued_funding as unknown as string), ), fees: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.realized_pnl.closing_fee as any).plus( - position.realized_pnl.opening_fee as any, + BN(position.realized_pnl.closing_fee as unknown as string).plus( + position.realized_pnl.opening_fee as unknown as string, ), ), }, unrealized: { net: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.unrealized_pnl.pnl as any), + BN(position.unrealized_pnl.pnl as unknown as string), ), price: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.unrealized_pnl.price_pnl as any), + BN(position.unrealized_pnl.price_pnl as unknown as string), ), funding: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.unrealized_pnl.accrued_funding as any), + BN(position.unrealized_pnl.accrued_funding as unknown as string), ), fees: BNCoin.fromDenomAndBigNumber( position.base_denom, - BN(position.unrealized_pnl.closing_fee as any), + BN(position.unrealized_pnl.closing_fee as unknown as string), ), }, },