From 8fad1882483e6df2b7ec264a57d4b1fe1555ebbf Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Mon, 12 Jun 2023 08:41:36 +0300 Subject: [PATCH 1/3] feat: Add yearn harvests schemas --- apps/common/schemas/yDaemonVaultsSchemas.ts | 36 ++++++++++--------- apps/common/schemas/ySchemas.ts | 15 ++++++++ apps/common/types/yearn.tsx | 34 ------------------ .../details/tabs/VaultDetailsStrategies.tsx | 8 ++--- .../details/tabs/VaultDetailsTabsWrapper.tsx | 6 ++-- apps/ybal/components/Harvests.tsx | 8 ++--- apps/ybal/contexts/useYBal.tsx | 29 ++++++--------- apps/ycrv/contexts/useYCRV.tsx | 25 ++++++------- 8 files changed, 67 insertions(+), 94 deletions(-) create mode 100644 apps/common/schemas/ySchemas.ts delete mode 100755 apps/common/types/yearn.tsx diff --git a/apps/common/schemas/yDaemonVaultsSchemas.ts b/apps/common/schemas/yDaemonVaultsSchemas.ts index 79d704df2..6df64b56e 100644 --- a/apps/common/schemas/yDaemonVaultsSchemas.ts +++ b/apps/common/schemas/yDaemonVaultsSchemas.ts @@ -60,6 +60,19 @@ const yDaemonVaultStrategySchema = z.object({ }).optional() // Optional for migratable }); +export const yDaemonVaultTokenSchema = z.object({ + address: addressSchema, + underlyingTokensAddresses: z.array(addressSchema), + name: z.string(), + symbol: z.string(), + type: z.string(), + display_name: z.string(), + display_symbol: z.string(), + description: z.string(), + icon: z.string(), + decimals: z.number() +}); + export const yDaemonVaultSchema = z.object({ address: addressSchema, type: z.literal('Automated').or(z.literal('Standard').or(z.literal('Experimental'))), @@ -78,18 +91,7 @@ export const yDaemonVaultSchema = z.object({ riskScore: z.number(), endorsed: z.boolean(), emergency_shutdown: z.boolean(), - token: z.object({ - address: addressSchema, - underlyingTokensAddresses: z.array(addressSchema), - name: z.string(), - symbol: z.string(), - type: z.string(), - display_name: z.string(), - display_symbol: z.string(), - description: z.string(), - icon: z.string(), - decimals: z.number() - }), + token: yDaemonVaultTokenSchema, tvl: z.object({ total_assets: z.string(), total_delegated_assets: z.string(), @@ -161,8 +163,8 @@ export const yDaemonVaultSchema = z.object({ export const yDaemonVaultsSchema = z.array(yDaemonVaultSchema); export const yDaemonVaultHarvestSchema = z.object({ - vaultAddress: z.string().optional(), - strategyAddress: z.string().optional(), + vaultAddress: addressSchema.optional(), + strategyAddress: addressSchema.optional(), txHash:z.string().optional(), timestamp: z.string(), profit: z.string(), @@ -179,6 +181,8 @@ export type TYDaemonVaultStrategy = z.infer; export type TYDaemonVaults = z.infer; -export type TYDaemonVaultHarvestSchema = z.infer; +export type TYDaemonVaultHarvest = z.infer; + +export type TYDaemonVaultHarvests = z.infer; -export type TYDaemonVaultHarvestsSchema = z.infer; +export type TYDaemonVaultTokenSchema = z.infer; diff --git a/apps/common/schemas/ySchemas.ts b/apps/common/schemas/ySchemas.ts new file mode 100644 index 000000000..5cd123ed3 --- /dev/null +++ b/apps/common/schemas/ySchemas.ts @@ -0,0 +1,15 @@ +import {z} from 'zod'; +import {addressSchema} from '@common/schemas/custom/addressSchema'; + +export const ySettingsForNetworkSchema = z.object({ + rpcURI: z.string().optional(), + yDaemonURI: z.string().optional(), + graphURI: z.string().optional(), + metaURI: z.string().optional(), + apiURI: z.string().optional(), + explorerBaseURI: z.string().optional(), + lensOracleAddress: addressSchema.optional(), + partnerContractAddress: addressSchema.optional() +}); + +export type TSettingsForNetwork = z.infer; diff --git a/apps/common/types/yearn.tsx b/apps/common/types/yearn.tsx deleted file mode 100755 index 641f19851..000000000 --- a/apps/common/types/yearn.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import type {TAddress} from '@yearn-finance/web-lib/types'; - -export type TYearnVaultToken = { - address: TAddress, - underlyingTokensAddresses: TAddress[], - name: string, - display_name: string, - symbol: string, - description: string, - decimals: number, - icon: string, -} - -export type TSettingsForNetwork = { - rpcURI?: string, - yDaemonURI?: string, - graphURI?: string, - metaURI?: string, - apiURI?: string, - explorerBaseURI?: string, - lensOracleAddress?: TAddress, - partnerContractAddress?: TAddress -} - -export type TYDaemonHarvests = { - vaultAddress: TAddress, - strategyAddress: TAddress, - txHash: string, - timestamp: string, - profit: string, - profitValue: number, - loss: string, - lossValue: number, -} diff --git a/apps/vaults/components/details/tabs/VaultDetailsStrategies.tsx b/apps/vaults/components/details/tabs/VaultDetailsStrategies.tsx index 7067492cf..f9b23eeb8 100755 --- a/apps/vaults/components/details/tabs/VaultDetailsStrategies.tsx +++ b/apps/vaults/components/details/tabs/VaultDetailsStrategies.tsx @@ -4,7 +4,6 @@ import {findLatestApr} from '@vaults/components/details/tabs/findLatestApr'; import {GraphForStrategyReports} from '@vaults/components/graphs/GraphForStrategyReports'; import {yDaemonReportsSchema} from '@vaults/schemas/reportsSchema'; import Renderable from '@yearn-finance/web-lib/components/Renderable'; -import {useSettings} from '@yearn-finance/web-lib/contexts/useSettings'; import {useChainID} from '@yearn-finance/web-lib/hooks/useChainID'; import IconCopy from '@yearn-finance/web-lib/icons/IconCopy'; import {toAddress} from '@yearn-finance/web-lib/utils/address'; @@ -16,6 +15,7 @@ import {SearchBar} from '@common/components/SearchBar'; import {Switch} from '@common/components/Switch'; import {useFetch} from '@common/hooks/useFetch'; import IconChevron from '@common/icons/IconChevron'; +import {useYDaemonBaseURI} from '@common/utils/getYDaemonBaseURI'; import type {ReactElement} from 'react'; import type {TYDaemonVault, TYDaemonVaultStrategy} from '@common/schemas/yDaemonVaultsSchemas'; @@ -43,7 +43,7 @@ function RiskScoreElement({label, value}: TRiskScoreElementProps): ReactElement function VaultDetailsStrategy({currentVault, strategy}: TProps): ReactElement { const {safeChainID} = useChainID(); - const {settings: baseAPISettings} = useSettings(); + const {yDaemonBaseUri} = useYDaemonBaseURI({chainID: safeChainID}); const isMounted = useIsMounted(); const riskScoreElementsMap = useMemo((): TRiskScoreElementProps[] => { @@ -61,10 +61,8 @@ function VaultDetailsStrategy({currentVault, strategy}: TProps): ReactElement { ]); }, [strategy]); - const YDAEMON_BASE_URI = `${baseAPISettings.yDaemonBaseURI || process.env.YDAEMON_BASE_URI}/${safeChainID}`; - const {data: reports} = useFetch({ - endpoint: `${YDAEMON_BASE_URI}/reports/${strategy.address}`, + endpoint: `${yDaemonBaseUri}/reports/${strategy.address}`, schema: yDaemonReportsSchema }); diff --git a/apps/vaults/components/details/tabs/VaultDetailsTabsWrapper.tsx b/apps/vaults/components/details/tabs/VaultDetailsTabsWrapper.tsx index 5e98f28a1..7ff8cc4e3 100755 --- a/apps/vaults/components/details/tabs/VaultDetailsTabsWrapper.tsx +++ b/apps/vaults/components/details/tabs/VaultDetailsTabsWrapper.tsx @@ -23,8 +23,8 @@ import {assert} from '@common/utils/assert'; import {useYDaemonBaseURI} from '@common/utils/getYDaemonBaseURI'; import type {ReactElement} from 'react'; -import type {TYDaemonVault, TYDaemonVaultHarvestsSchema} from '@common/schemas/yDaemonVaultsSchemas'; -import type {TSettingsForNetwork} from '@common/types/yearn'; +import type {TYDaemonVault, TYDaemonVaultHarvests} from '@common/schemas/yDaemonVaultsSchemas'; +import type {TSettingsForNetwork} from '@common/schemas/ySchemas'; type TTabsOptions = { value: number; @@ -176,7 +176,7 @@ function VaultDetailsTabsWrapper({currentVault}: {currentVault: TYDaemonVault}): } } - const {data: yDaemonHarvestsData} = useFetch({ + const {data: yDaemonHarvestsData} = useFetch({ endpoint: `${yDaemonBaseUri}/vaults/harvests/${currentVault.address}`, schema: yDaemonVaultHarvestsSchema }); diff --git a/apps/ybal/components/Harvests.tsx b/apps/ybal/components/Harvests.tsx index 165b5bb44..8b35fcdcd 100644 --- a/apps/ybal/components/Harvests.tsx +++ b/apps/ybal/components/Harvests.tsx @@ -7,13 +7,13 @@ import {HarvestListRow} from '@yBal/components/HarvestsListRow'; import {useYBal} from '@yBal/contexts/useYBal'; import type {ReactElement} from 'react'; -import type {TYDaemonHarvests} from '@common/types/yearn'; +import type {TYDaemonVaultHarvest, TYDaemonVaultHarvests} from '@common/schemas/yDaemonVaultsSchemas'; function Harvests(): ReactElement { const {harvests} = useYBal(); const [category, set_category] = useState('all'); - const filteredHarvests = useMemo((): TYDaemonHarvests[] => { + const filteredHarvests = useMemo((): TYDaemonVaultHarvests => { const _harvests = [...(harvests || [])]; if (category === 'st-yBal') { return _harvests.filter((harvest): boolean => toAddress(harvest.vaultAddress) === STYBAL_TOKEN_ADDRESS); @@ -55,12 +55,12 @@ function Harvests(): ReactElement { { (filteredHarvests || []) - .filter((harvest: TYDaemonHarvests): boolean => { + .filter((harvest: TYDaemonVaultHarvest): boolean => { return ( !isZeroAddress(toAddress(harvest.vaultAddress)) && [STYBAL_TOKEN_ADDRESS, LPYBAL_TOKEN_ADDRESS].includes(toAddress(harvest.vaultAddress)) ); - }).map((harvest: TYDaemonHarvests, index: number): ReactElement => { + }).map((harvest: TYDaemonVaultHarvest, index: number): ReactElement => { return ( , holdings: TBalHoldings, - harvests: TYDaemonHarvests[], + harvests: TYDaemonVaultHarvests, set_slippage: (slippage: number) => void, refetchAllowances: () => void } @@ -41,23 +37,20 @@ const defaultProps = { const YBalContext = createContext(defaultProps); export const YBalContextApp = ({children}: {children: ReactElement}): ReactElement => { - const {settings: baseAPISettings} = useSettings(); + const {yDaemonBaseUri} = useYDaemonBaseURI({chainID: 1}); const [slippage, set_slippage] = useState(0.6); const holdings = useHoldings(); const allowances = useAllowances(); - const YDAEMON_BASE_URI = `${baseAPISettings.yDaemonBaseURI || process.env.YDAEMON_BASE_URI}`; - const {data: styBalVault} = useFetch({ - endpoint: `${YDAEMON_BASE_URI}/1/vaults/${STYBAL_TOKEN_ADDRESS}`, + endpoint: `${yDaemonBaseUri}/vaults/${STYBAL_TOKEN_ADDRESS}`, schema: yDaemonVaultSchema }); - const {data: yBalHarvests} = useSWR( - `${YDAEMON_BASE_URI}/1/vaults/harvests/${STYBAL_TOKEN_ADDRESS},${LPYBAL_TOKEN_ADDRESS}`, - baseFetcher, - {revalidateOnFocus: false} - ) as SWRResponse; + const {data: yBalHarvests} = useFetch({ + endpoint: `${yDaemonBaseUri}/vaults/harvests/${STYBAL_TOKEN_ADDRESS},${LPYBAL_TOKEN_ADDRESS}`, + schema: yDaemonVaultHarvestsSchema + }); /* 🔵 - Yearn Finance ****************************************************** ** Compute the styBal APY based on the experimental APY and the mega boost. @@ -68,7 +61,7 @@ export const YBalContextApp = ({children}: {children: ReactElement}): ReactEleme ** Setup and render the Context provider to use in the app. ***************************************************************************/ const contextValue = useMemo((): TYBalContext => ({ - harvests: yBalHarvests, + harvests: yBalHarvests ?? [], holdings: holdings, allowances: allowances[0], refetchAllowances: allowances[1], diff --git a/apps/ycrv/contexts/useYCRV.tsx b/apps/ycrv/contexts/useYCRV.tsx index 4e312b2d0..d7f005b7e 100755 --- a/apps/ycrv/contexts/useYCRV.tsx +++ b/apps/ycrv/contexts/useYCRV.tsx @@ -1,21 +1,18 @@ import React, {createContext, useContext, useMemo, useState} from 'react'; import {formatUnits} from 'viem'; -import useSWR from 'swr'; +import {useChainID} from '@yearn-finance/web-lib/hooks/useChainID'; import {LPYCRV_TOKEN_ADDRESS, STYCRV_TOKEN_ADDRESS} from '@yearn-finance/web-lib/utils/constants'; -import {baseFetcher} from '@yearn-finance/web-lib/utils/fetchers'; import {isZero} from '@yearn-finance/web-lib/utils/isZero'; import {useFetch} from '@common/hooks/useFetch'; -import {yDaemonVaultSchema} from '@common/schemas/yDaemonVaultsSchemas'; +import {yDaemonVaultHarvestsSchema, yDaemonVaultSchema} from '@common/schemas/yDaemonVaultsSchemas'; import {useYDaemonBaseURI} from '@common/utils/getYDaemonBaseURI'; import {useAllowances} from '@yCRV/contexts/useAllowanceHook'; import {defaultHoldings, useHoldings} from '@yCRV/contexts/useHoldingsHook'; import type {ReactElement} from 'react'; -import type {SWRResponse} from 'swr'; import type {TCRVHoldings} from '@yCRV/contexts/useHoldingsHook'; import type {TDict} from '@yearn-finance/web-lib/types'; -import type {TYDaemonVault} from '@common/schemas/yDaemonVaultsSchemas'; -import type {TYDaemonHarvests} from '@common/types/yearn'; +import type {TYDaemonVault, TYDaemonVaultHarvests} from '@common/schemas/yDaemonVaultsSchemas'; type TYCRVContext = { styCRVMegaBoost: number, @@ -23,7 +20,7 @@ type TYCRVContext = { slippage: number, allowances: TDict, holdings: TCRVHoldings, - harvests: TYDaemonHarvests[], + harvests: TYDaemonVaultHarvests, set_slippage: (slippage: number) => void, refetchAllowances: () => void } @@ -44,7 +41,8 @@ const defaultProps = { ******************************************************************************/ const YCRVContext = createContext(defaultProps); export const YCRVContextApp = ({children}: {children: ReactElement}): ReactElement => { - const {yDaemonBaseUri} = useYDaemonBaseURI({chainID: 1}); + const {safeChainID} = useChainID(); + const {yDaemonBaseUri} = useYDaemonBaseURI({chainID: safeChainID}); const [slippage, set_slippage] = useState(0.6); const holdings = useHoldings(); const allowances = useAllowances(); @@ -54,11 +52,10 @@ export const YCRVContextApp = ({children}: {children: ReactElement}): ReactEleme schema: yDaemonVaultSchema }); - const {data: yCRVHarvests} = useSWR( - `${yDaemonBaseUri}/vaults/harvests/${STYCRV_TOKEN_ADDRESS},${LPYCRV_TOKEN_ADDRESS}`, - baseFetcher, - {revalidateOnFocus: false} - ) as SWRResponse; + const {data: yCRVHarvests} = useFetch({ + endpoint: `${yDaemonBaseUri}/vaults/harvests/${STYCRV_TOKEN_ADDRESS},${LPYCRV_TOKEN_ADDRESS}`, + schema: yDaemonVaultHarvestsSchema + }); /* 🔵 - Yearn Finance ****************************************************** ** Compute the mega boost for the staked yCRV. This boost come from the @@ -87,7 +84,7 @@ export const YCRVContextApp = ({children}: {children: ReactElement}): ReactEleme ** Setup and render the Context provider to use in the app. ***************************************************************************/ const contextValue = useMemo((): TYCRVContext => ({ - harvests: yCRVHarvests, + harvests: yCRVHarvests ?? [], holdings: holdings, allowances: allowances[0], refetchAllowances: allowances[1], From 5cde6e09843a2c3540f10c7958ce69d225486761 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Mon, 12 Jun 2023 10:58:10 +0300 Subject: [PATCH 2/3] build: Fix build errors --- apps/ybal/components/HarvestsListRow.tsx | 4 ++-- apps/ycrv/components/Harvests.tsx | 6 +++--- apps/ycrv/components/HarvestsListRow.tsx | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/ybal/components/HarvestsListRow.tsx b/apps/ybal/components/HarvestsListRow.tsx index 1b2346ebd..5b9834b98 100755 --- a/apps/ybal/components/HarvestsListRow.tsx +++ b/apps/ybal/components/HarvestsListRow.tsx @@ -9,7 +9,7 @@ import {formatDate} from '@yearn-finance/web-lib/utils/format.time'; import {ImageWithFallback} from '@common/components/ImageWithFallback'; import type {ReactElement} from 'react'; -import type {TYDaemonHarvests} from '@common/types/yearn'; +import type {TYDaemonVaultHarvest} from '@common/schemas/yDaemonVaultsSchemas'; type TRowProps = { label: string; @@ -28,7 +28,7 @@ function Row({label, value, className, valueClassName}: TRowProps): ReactElement ); } -function HarvestListRow({harvest}: {harvest: TYDaemonHarvests}): ReactElement { +function HarvestListRow({harvest}: {harvest: TYDaemonVaultHarvest}): ReactElement { const vaultName = toAddress(harvest.vaultAddress) === STYBAL_TOKEN_ADDRESS ? 'st-yBal' : 'lp-yBal'; const gain = formatToNormalizedAmount(toBigInt(harvest.profit) - toBigInt(harvest.loss)); const value = formatUSD(Number(harvest.profitValue) - Number(harvest.lossValue)); diff --git a/apps/ycrv/components/Harvests.tsx b/apps/ycrv/components/Harvests.tsx index fd2d7e87e..c71f1b56b 100644 --- a/apps/ycrv/components/Harvests.tsx +++ b/apps/ycrv/components/Harvests.tsx @@ -7,13 +7,13 @@ import {HarvestListRow} from '@yCRV/components/HarvestsListRow'; import {useYCRV} from '@yCRV/contexts/useYCRV'; import type {ReactElement} from 'react'; -import type {TYDaemonHarvests} from '@common/types/yearn'; +import type {TYDaemonVaultHarvest, TYDaemonVaultHarvests} from '@common/schemas/yDaemonVaultsSchemas'; function Harvests(): ReactElement { const {harvests} = useYCRV(); const [category, set_category] = useState('all'); - const filteredHarvests = useMemo((): TYDaemonHarvests[] => { + const filteredHarvests = useMemo((): TYDaemonVaultHarvests => { const _harvests = [...(harvests || [])]; if (category === 'st-yCRV') { return _harvests.filter((harvest): boolean => toAddress(harvest.vaultAddress) === STYCRV_TOKEN_ADDRESS); @@ -53,7 +53,7 @@ function Harvests(): ReactElement {
- {(filteredHarvests || [])?.map((harvest: TYDaemonHarvests, index: number): ReactElement => { + {(filteredHarvests || [])?.map((harvest: TYDaemonVaultHarvest, index: number): ReactElement => { return ; })}
diff --git a/apps/ycrv/components/HarvestsListRow.tsx b/apps/ycrv/components/HarvestsListRow.tsx index 6142bcc9d..633340600 100755 --- a/apps/ycrv/components/HarvestsListRow.tsx +++ b/apps/ycrv/components/HarvestsListRow.tsx @@ -8,9 +8,9 @@ import {formatDate} from '@yearn-finance/web-lib/utils/format.time'; import {ImageWithFallback} from '@common/components/ImageWithFallback'; import type {ReactElement} from 'react'; -import type {TYDaemonHarvests} from '@common/types/yearn'; +import type {TYDaemonVaultHarvest} from '@common/schemas/yDaemonVaultsSchemas'; -function HarvestListRow({harvest}: {harvest: TYDaemonHarvests}): ReactElement { +function HarvestListRow({harvest}: {harvest: TYDaemonVaultHarvest}): ReactElement { return (
From a19da076c4c537022355bebc6661aae439505241 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Mon, 12 Jun 2023 11:37:28 +0300 Subject: [PATCH 3/3] refactor: Hardcode network --- apps/ycrv/contexts/useYCRV.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/ycrv/contexts/useYCRV.tsx b/apps/ycrv/contexts/useYCRV.tsx index d7f005b7e..586ba1f20 100755 --- a/apps/ycrv/contexts/useYCRV.tsx +++ b/apps/ycrv/contexts/useYCRV.tsx @@ -1,6 +1,5 @@ import React, {createContext, useContext, useMemo, useState} from 'react'; import {formatUnits} from 'viem'; -import {useChainID} from '@yearn-finance/web-lib/hooks/useChainID'; import {LPYCRV_TOKEN_ADDRESS, STYCRV_TOKEN_ADDRESS} from '@yearn-finance/web-lib/utils/constants'; import {isZero} from '@yearn-finance/web-lib/utils/isZero'; import {useFetch} from '@common/hooks/useFetch'; @@ -41,8 +40,7 @@ const defaultProps = { ******************************************************************************/ const YCRVContext = createContext(defaultProps); export const YCRVContextApp = ({children}: {children: ReactElement}): ReactElement => { - const {safeChainID} = useChainID(); - const {yDaemonBaseUri} = useYDaemonBaseURI({chainID: safeChainID}); + const {yDaemonBaseUri} = useYDaemonBaseURI({chainID: 1}); const [slippage, set_slippage] = useState(0.6); const holdings = useHoldings(); const allowances = useAllowances();