From 93c7ad938206a832cafe3e9097ecb0aca8497187 Mon Sep 17 00:00:00 2001 From: martines3000 Date: Fri, 10 Jan 2025 15:48:31 +0100 Subject: [PATCH 1/4] feat: initial work on lm rewards display --- .gitignore | 1 + apps/frontend/package.json | 1 + .../DashboardView/Stats/InfoBowl.tsx | 39 ++---- apps/frontend/src/configs/envs/mainnet.ts | 18 ++- apps/frontend/src/configs/envs/testnet.ts | 8 +- apps/frontend/src/configs/types.ts | 17 +++ apps/frontend/src/hooks/useApr.ts | 56 +++++++++ apps/frontend/src/hooks/useRewards.ts | 117 ++++++++++++++++++ pnpm-lock.yaml | 3 + 9 files changed, 230 insertions(+), 30 deletions(-) create mode 100644 apps/frontend/src/hooks/useApr.ts create mode 100644 apps/frontend/src/hooks/useRewards.ts diff --git a/.gitignore b/.gitignore index 45023cd4..0d4e5865 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ build dist .env .DS_Store +scripts \ No newline at end of file diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 50235cdc..57c885d2 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -34,6 +34,7 @@ "bignumber.js": "^9.1.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "dayjs": "^1.11.13", "encoding": "^0.1.13", "fuels": "0.96.1", "lucide-react": "^0.460.0", diff --git a/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx b/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx index a1692bea..a2961080 100644 --- a/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx +++ b/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx @@ -5,16 +5,11 @@ import { TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; -import { - useBorrowRate, - useSupplyRate, - useUserCollateralAssets, - useUserSupplyBorrow, -} from '@/hooks'; +import { useUserCollateralAssets, useUserSupplyBorrow } from '@/hooks'; +import { useApr } from '@/hooks/useApr'; import { useUserCollateralUtilization } from '@/hooks/useUserCollateralUtilization'; import { cn } from '@/lib/utils'; import { selectMarketMode, useMarketStore } from '@/stores'; -import { getBorrowApr, getSupplyApr } from '@/utils'; import { useIsConnected } from '@fuels/react'; import { useMemo } from 'react'; import Wave from 'react-wavify'; @@ -38,8 +33,7 @@ const WAVE_COLORS = { export const InfoBowl = () => { const marketMode = useMarketStore(selectMarketMode); const { isConnected } = useIsConnected(); - const { data: borrowRate, isPending: isPendingBorrowRate } = useBorrowRate(); - const { data: supplyRate, isPending: isPendingSupplyRate } = useSupplyRate(); + const { data: userSupplyBorrow, isPending: isPendingUserSupplyBorrow } = useUserSupplyBorrow(); const { data: collateralUtilization } = useUserCollateralUtilization(); @@ -70,23 +64,12 @@ export const InfoBowl = () => { return WAVE_COLORS.danger; }, [collateralUtilization, collateralBalances]); - const borrowApr = useMemo(() => getBorrowApr(borrowRate), [borrowRate]); - - const supplyApr = useMemo(() => getSupplyApr(supplyRate), [supplyRate]); + const { data: aprData, isPending: isAprPending } = useApr(); const isLoading = useMemo(() => { - if (!isConnected) return isPendingBorrowRate || isPendingSupplyRate; - return [ - isPendingBorrowRate, - isPendingSupplyRate, - isPendingUserSupplyBorrow, - ].some((res) => res); - }, [ - isConnected, - isPendingBorrowRate, - isPendingSupplyRate, - isPendingUserSupplyBorrow, - ]); + if (!isConnected) return isAprPending; + return [isPendingUserSupplyBorrow, isAprPending].some((res) => res); + }, [isConnected, isAprPending, isPendingUserSupplyBorrow]); return ( @@ -165,17 +148,17 @@ export const InfoBowl = () => { )} {bowlMode === 1 && (
- Borrow APY + Net Borrow APY
- {borrowApr} + {aprData?.netBorrowApr.times(100).toFixed(2)}%
)} {bowlMode === 0 && (
- Supply APY + Net Supply APY
- {supplyApr} + {aprData?.netSupplyApr.times(100).toFixed(2)}%
)} diff --git a/apps/frontend/src/configs/envs/mainnet.ts b/apps/frontend/src/configs/envs/mainnet.ts index 10210c8b..a0ffac00 100644 --- a/apps/frontend/src/configs/envs/mainnet.ts +++ b/apps/frontend/src/configs/envs/mainnet.ts @@ -1,5 +1,5 @@ import { defineConfig } from '../defineConfig'; -import type { DeployedMarkets } from '../types'; +import type { DeployedMarkets, Rewards } from '../types'; export function createMainnetConfig() { return defineConfig({ @@ -28,6 +28,7 @@ export function createMainnetConfig() { markets: markets, assets: assets, useBurnerWallet: false, + rewards: rewards, }); } @@ -42,6 +43,21 @@ const markets: DeployedMarkets = { }, }; +const rewards: Rewards = { + USDC: [ + { + poolSize: 2000000, + assetId: + '0x1d5d97005e41cae2187a895fd8eab0506111e0e2f3331cd3912c15c24e3c1d82', + supplyRewardPercentage: 0.5, + borrowRewardPercentage: 0.5, + startDate: '2025-01-10T00:00:00Z', + endDate: '2025-01-17T00:00:00Z', + durationInDays: 7, + }, + ], +}; + const assets: Record = { '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07': 'ETH', '0x286c479da40dc953bddc3bb4c453b608bba2e0ac483b077bd475174115395e6b': 'USDC', diff --git a/apps/frontend/src/configs/envs/testnet.ts b/apps/frontend/src/configs/envs/testnet.ts index 3bdfc5aa..7f259a7d 100644 --- a/apps/frontend/src/configs/envs/testnet.ts +++ b/apps/frontend/src/configs/envs/testnet.ts @@ -1,5 +1,5 @@ import { defineConfig } from '../defineConfig'; -import type { DeployedMarkets } from '../types'; +import type { DeployedMarkets, Rewards } from '../types'; export function createTestnetConfig() { return defineConfig({ @@ -28,9 +28,15 @@ export function createTestnetConfig() { baseAssetId: '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07', useBurnerWallet: true, + rewards: rewards, }); } +const rewards: Rewards = { + USDC: [], + USDT: [], +}; + const markets: DeployedMarkets = { USDC: { oracleAddress: diff --git a/apps/frontend/src/configs/types.ts b/apps/frontend/src/configs/types.ts index b66c56a3..e0847479 100644 --- a/apps/frontend/src/configs/types.ts +++ b/apps/frontend/src/configs/types.ts @@ -10,6 +10,21 @@ export const DeployedMarketsSchema = z.record( }) ); +export const RewardsSchema = z.record( + z.string(), + z.array( + z.object({ + poolSize: z.number(), + assetId: z.string(), + supplyRewardPercentage: z.number(), + borrowRewardPercentage: z.number(), + startDate: z.string(), + endDate: z.string(), + durationInDays: z.number(), + }) + ) +); + export const AppConfigSchema = z.object({ env: z.enum(['testnet', 'mainnet']), client: z.object({ @@ -33,7 +48,9 @@ export const AppConfigSchema = z.object({ assets: z.record(z.string(), z.string()), baseAssetId: z.string(), useBurnerWallet: z.boolean(), + rewards: RewardsSchema, }); export type AppConfig = z.infer; export type DeployedMarkets = z.infer; +export type Rewards = z.infer; diff --git a/apps/frontend/src/hooks/useApr.ts b/apps/frontend/src/hooks/useApr.ts new file mode 100644 index 00000000..d80af7a1 --- /dev/null +++ b/apps/frontend/src/hooks/useApr.ts @@ -0,0 +1,56 @@ +import { selectMarket, useMarketStore } from '@/stores'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import BigNumber from 'bignumber.js'; +import { useBorrowRate } from './useBorrowRate'; +import { useRewards } from './useRewards'; +import { useSupplyRate } from './useSupplyRate'; + +const COEFFICIENT = BigNumber(365).times(24).times(60).times(60); + +export const useApr = (marketParam?: string) => { + const storeMarket = useMarketStore(selectMarket); + const market = marketParam ?? storeMarket; + const { data: rewardsData } = useRewards(market); + const { data: supplyRate } = useSupplyRate(market); + const { data: borrowRate } = useBorrowRate(market); + + return useQuery({ + queryKey: ['apr', supplyRate, borrowRate, rewardsData], + queryFn: async () => { + if (!supplyRate || !borrowRate || !rewardsData) { + return { + supplyBaseApr: BigNumber(0), + borrowBaseApr: BigNumber(0), + supplyRewardApr: BigNumber(0), + borrowRewardApr: BigNumber(0), + netSupplyApr: BigNumber(0), + netBorrowApr: BigNumber(0), + }; + } + + const { borrowRewardApr, supplyRewardApr } = rewardsData; + + const supplyBaseApr = supplyRate + .times(COEFFICIENT) + .dividedBy(BigNumber(10).pow(18)); + const borrowBaseApr = borrowRate + .times(COEFFICIENT) + .dividedBy(BigNumber(10).pow(18)); + + const netSupplyApr = supplyBaseApr.plus(supplyRewardApr); + const netBorrowApr = borrowBaseApr.minus(borrowRewardApr); + + return { + supplyBaseApr, + borrowBaseApr, + supplyRewardApr: supplyRewardApr, + borrowRewardApr: borrowRewardApr, + netSupplyApr, + netBorrowApr, + }; + }, + enabled: !!supplyRate && !!borrowRate && !!rewardsData, + refetchOnWindowFocus: false, + placeholderData: keepPreviousData, + }); +}; diff --git a/apps/frontend/src/hooks/useRewards.ts b/apps/frontend/src/hooks/useRewards.ts new file mode 100644 index 00000000..4f3e26a9 --- /dev/null +++ b/apps/frontend/src/hooks/useRewards.ts @@ -0,0 +1,117 @@ +import { appConfig } from '@/configs'; +import { selectMarket, useMarketStore } from '@/stores'; +import { useQuery } from '@tanstack/react-query'; +import BigNumber from 'bignumber.js'; +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; +import { useMemo } from 'react'; +import { useMarketBasicsWithInterest } from './useMarketBasicsWithInterest'; +import { useMarketConfiguration } from './useMarketConfiguration'; +import { usePrice } from './usePrice'; + +dayjs.extend(utc); + +const calculateRewardsAprForPool = ( + tokenAmount: BigNumber, + tokenPrice: BigNumber, + durationInDays: number, + currentTvl: BigNumber +) => { + return tokenAmount + .times(tokenPrice) + .times(365) + .dividedBy(durationInDays) + .dividedBy(currentTvl); +}; + +export const useRewards = (marketParam?: string) => { + const storeMarket = useMarketStore(selectMarket); + const market = marketParam ?? storeMarket; + + const { data: marketBasics } = useMarketBasicsWithInterest(market); + const { data: priceData } = usePrice(market); + const { data: marketConfiguration } = useMarketConfiguration(market); + + return useQuery({ + queryKey: [ + 'rewards', + market, + marketBasics, + priceData?.prices, + marketConfiguration, + ], + queryFn: async () => { + if (!marketBasics || !priceData || !marketConfiguration) { + return { + supplyRewardApr: BigNumber(0), + borrowRewardApr: BigNumber(0), + }; + } + + const rewardsConfig = appConfig.rewards[market]; + + const today = dayjs().utc().startOf('day'); + const activeRewards = rewardsConfig.filter((reward) => { + return ( + (today.isAfter(dayjs(reward.startDate).utc().startOf('day')) || + today.isSame(dayjs(reward.startDate).utc().startOf('day'))) && + today.isBefore(dayjs(reward.endDate).utc().startOf('day')) + ); + }); + + const { total_borrow_base, total_supply_base } = marketBasics; + + const totalBorrowValue = BigNumber(total_borrow_base.toString()) + .times(priceData.prices[marketConfiguration.baseToken.bits]) + .dividedBy(BigNumber(10).pow(marketConfiguration.baseTokenDecimals)); + + const totalSupplyValue = BigNumber(total_supply_base.toString()) + .times(priceData.prices[marketConfiguration.baseToken.bits]) + .dividedBy(BigNumber(10).pow(marketConfiguration.baseTokenDecimals)); + + return activeRewards + .map((reward) => { + const tokenPrice = priceData.prices[reward.assetId]; + const durationInDays = reward.durationInDays; + const supplyRewardPool = BigNumber(reward.poolSize).times( + reward.supplyRewardPercentage + ); + const borrowRewardPool = BigNumber(reward.poolSize).times( + reward.borrowRewardPercentage + ); + + const supplyRewardApr = calculateRewardsAprForPool( + supplyRewardPool, + tokenPrice, + durationInDays, + totalSupplyValue + ); + const borrowRewardApr = calculateRewardsAprForPool( + borrowRewardPool, + tokenPrice, + durationInDays, + totalBorrowValue + ); + + return { + supplyRewardApr, + borrowRewardApr, + }; + }) + .reduce( + (acc, curr) => { + return { + supplyRewardApr: acc.supplyRewardApr.plus(curr.supplyRewardApr), + borrowRewardApr: acc.borrowRewardApr.plus(curr.borrowRewardApr), + }; + }, + { + supplyRewardApr: BigNumber(0), + borrowRewardApr: BigNumber(0), + } + ); + }, + enabled: !!marketBasics && !!priceData && !!marketConfiguration, + refetchOnWindowFocus: false, + }); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1868254..789a5499 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,6 +102,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 encoding: specifier: ^0.1.13 version: 0.1.13 From d613ff8a3751952a0f0a356752b9727327d2a978 Mon Sep 17 00:00:00 2001 From: martines3000 Date: Fri, 10 Jan 2025 15:54:47 +0100 Subject: [PATCH 2/4] chore: imports --- apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx | 2 +- apps/frontend/src/hooks/index.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx b/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx index a2961080..38827adb 100644 --- a/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx +++ b/apps/frontend/src/components/DashboardView/Stats/InfoBowl.tsx @@ -6,7 +6,7 @@ import { TooltipTrigger, } from '@/components/ui/tooltip'; import { useUserCollateralAssets, useUserSupplyBorrow } from '@/hooks'; -import { useApr } from '@/hooks/useApr'; +import { useApr } from '@/hooks'; import { useUserCollateralUtilization } from '@/hooks/useUserCollateralUtilization'; import { cn } from '@/lib/utils'; import { selectMarketMode, useMarketStore } from '@/stores'; diff --git a/apps/frontend/src/hooks/index.ts b/apps/frontend/src/hooks/index.ts index 4d813afe..7817b298 100644 --- a/apps/frontend/src/hooks/index.ts +++ b/apps/frontend/src/hooks/index.ts @@ -29,3 +29,4 @@ export * from './useTotalReserves'; export * from './useCollateralReserves'; export * from './useMaxWithdrawableCollateral'; export * from './useProvider'; +export * from './useApr'; From 42c3e4dc5caada61a437e98ef873312fd25d4ea5 Mon Sep 17 00:00:00 2001 From: Andy <69682837+andyv09@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:32:48 +0100 Subject: [PATCH 3/4] feat: add LM tooltips & update tables (#235) --- .../DashboardView/AssetsTable/BorrowTable.tsx | 170 +++++++++++++++--- .../DashboardView/AssetsTable/LendTable.tsx | 155 ++++++++++++++-- .../components/MarketsView/MarketOverview.tsx | 128 +++++++++++-- .../components/MarketsView/MarketTableRow.tsx | 104 +++++++++-- .../components/PointIcons/PointsTooltip.tsx | 12 +- .../Providers/FuelProviderWrapper.tsx | 2 +- 6 files changed, 511 insertions(+), 60 deletions(-) diff --git a/apps/frontend/src/components/DashboardView/AssetsTable/BorrowTable.tsx b/apps/frontend/src/components/DashboardView/AssetsTable/BorrowTable.tsx index 0b00f9f6..8b8646f7 100644 --- a/apps/frontend/src/components/DashboardView/AssetsTable/BorrowTable.tsx +++ b/apps/frontend/src/components/DashboardView/AssetsTable/BorrowTable.tsx @@ -1,6 +1,10 @@ import { InfoIcon } from '@/components/InfoIcon'; +import { Line } from '@/components/Line'; import { PointIcons } from '@/components/PointIcons'; -import { POINTS_BORROW } from '@/components/PointIcons/PointsTooltip'; +import { + POINTS_BORROW, + POINTS_LM, +} from '@/components/PointIcons/PointsTooltip'; import { Title } from '@/components/Title'; import { Button } from '@/components/ui/button'; import { @@ -20,12 +24,18 @@ import { TableHeader, TableRow, } from '@/components/ui/table'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@/components/ui/tooltip'; import { appConfig } from '@/configs'; import { USER_ROLE, + useApr, useBalance, useBorrowCapacity, - useBorrowRate, useMarketConfiguration, usePrice, useUserRole, @@ -40,12 +50,7 @@ import { selectChangeTokenAmount, useMarketStore, } from '@/stores'; -import { - SYMBOL_TO_ICON, - formatUnits, - getBorrowApr, - getFormattedNumber, -} from '@/utils'; +import { SYMBOL_TO_ICON, formatUnits, getFormattedNumber } from '@/utils'; import { useAccount, useIsConnected } from '@fuels/react'; import * as VisuallyHidden from '@radix-ui/react-visually-hidden'; import BigNumber from 'bignumber.js'; @@ -66,6 +71,12 @@ const SkeletonRow = ( + + + + + +
+
+
Borrow APY
+ +
+
+
Borrow APY
+ +
Supply Points
@@ -111,7 +130,6 @@ export const BorrowTable = () => { ); const changeInputDialogOpen = useMarketStore(selectChangeInputDialogOpen); - const { data: borrowRate, isPending: isBorrowRatePending } = useBorrowRate(); const { data: userSupplyBorrow } = useUserSupplyBorrow(); const { data: priceData } = usePrice(); const { data: marketConfiguration, isPending: isPendingMarketConfiguration } = @@ -125,6 +143,8 @@ export const BorrowTable = () => { changeInputDialogOpen(true); }; + const { data: aprData, isPending: isAprPending } = useApr(); + const { isConnected } = useIsConnected(); const { data: balance } = useBalance({ @@ -161,7 +181,7 @@ export const BorrowTable = () => { - +
Borrow Asset { />
- Borrow APY - Your Borrow Position - + Borrow APY + Your Borrow Position + +
+ Reward APY + +
+
+ +
+ Net APY + +
+
+
Borrow Points { />
- {} + {}
- {isPendingMarketConfiguration ? ( + {isPendingMarketConfiguration || isAprPending ? ( SkeletonRow ) : ( @@ -239,13 +279,74 @@ export const BorrowTable = () => { - {getBorrowApr(borrowRate)} + {aprData?.borrowBaseApr.times(100).toFixed(2)}% {borrowedBalance} + +
+ {aprData?.borrowRewardApr.times(100).toFixed(2)}% + +
+
+ + + + any }) => + e.preventDefault() + } + > +
{aprData?.netBorrowApr.times(100).toFixed(2)}%
+
+ any; + }) => e.preventDefault()} + > +
+
+ Net Borrow APY +
+
+
+
Borrow APY
+
+ {aprData?.borrowBaseApr.times(100).toFixed(2)}% +
+
+
+
Reward APY
+
+ {aprData?.borrowRewardApr.times(100).toFixed(2)}% +
+
+
+ +
+
Net Borrow APY
+
+ {aprData?.netBorrowApr.times(100).toFixed(2)}% +
+
+
+
+
+
+
@@ -307,7 +408,7 @@ export const BorrowTable = () => { Card Description - {isPendingMarketConfiguration ? ( + {isPendingMarketConfiguration || isAprPending ? ( SkeletonCardContent ) : ( @@ -365,10 +466,10 @@ export const BorrowTable = () => {
- {getBorrowApr(borrowRate)} + {aprData?.borrowBaseApr.times(100).toFixed(2)}%
@@ -377,6 +478,35 @@ export const BorrowTable = () => {
{borrowedBalance}
+
+
+ Reward APY +
+
+
+ {aprData?.borrowRewardApr.times(100).toFixed(2)}% + +
+
+
+
+
+ Net APY +
+
+ {aprData?.netBorrowApr.times(100).toFixed(2)}% +
+
Borrow Points diff --git a/apps/frontend/src/components/DashboardView/AssetsTable/LendTable.tsx b/apps/frontend/src/components/DashboardView/AssetsTable/LendTable.tsx index 61b1bb1c..fdb2e64c 100644 --- a/apps/frontend/src/components/DashboardView/AssetsTable/LendTable.tsx +++ b/apps/frontend/src/components/DashboardView/AssetsTable/LendTable.tsx @@ -1,6 +1,7 @@ import { InfoIcon } from '@/components/InfoIcon'; +import { Line } from '@/components/Line'; import { PointIcons } from '@/components/PointIcons'; -import { POINTS_LEND } from '@/components/PointIcons/PointsTooltip'; +import { POINTS_LEND, POINTS_LM } from '@/components/PointIcons/PointsTooltip'; import { Title } from '@/components/Title'; import { Button } from '@/components/ui/button'; import { @@ -20,9 +21,16 @@ import { TableHeader, TableRow, } from '@/components/ui/table'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@/components/ui/tooltip'; import { appConfig } from '@/configs'; import { USER_ROLE, + useApr, useBalance, useMarketConfiguration, useSupplyRate, @@ -63,6 +71,12 @@ const SkeletonRow = ( + + + + + +
+
+
Reward APY
+ +
+
+
Net APY
+ +
Supply Points
@@ -108,7 +130,6 @@ export const LendTable = () => { ); const changeInputDialogOpen = useMarketStore(selectChangeInputDialogOpen); - const { data: supplyRate, isPending: isSupplyRatePending } = useSupplyRate(); const { data: userSupplyBorrow } = useUserSupplyBorrow(); const { data: marketConfiguration, isPending: isPendingMarketConfiguration } = useMarketConfiguration(); @@ -125,6 +146,8 @@ export const LendTable = () => { assetId: marketConfiguration?.baseToken.bits, }); + const { data: aprData, isPending: isAprPending } = useApr(); + const userRole = useUserRole(); return ( @@ -133,15 +156,35 @@ export const LendTable = () => {
- +
Earn Asset
- Supply APY - Your Supplied Assets - + Supply APY + Your Supplied Assets + +
+ Reward APY + +
+
+ +
+ Net APY + +
+
+
Earn Points { />
- {} + {}
- {isPendingMarketConfiguration ? ( + {isPendingMarketConfiguration || isAprPending ? ( SkeletonRow ) : ( @@ -205,11 +248,11 @@ export const LendTable = () => { - {getSupplyApr(supplyRate)} + {aprData?.supplyBaseApr.times(100).toFixed(2)}% {getFormattedNumber( @@ -220,6 +263,67 @@ export const LendTable = () => { )}{' '} {appConfig.assets[marketConfiguration?.baseToken.bits ?? '']} + +
+ {aprData?.supplyRewardApr.times(100).toFixed(2)}% + +
+
+ + + + any }) => + e.preventDefault() + } + > +
{aprData?.netSupplyApr.times(100).toFixed(2)}%
+
+ any; + }) => e.preventDefault()} + > +
+
+ Net Earn APY +
+
+
+
Supply APY
+
+ {aprData?.supplyBaseApr.times(100).toFixed(2)}% +
+
+
+
Reward APY
+
+ {aprData?.supplyRewardApr.times(100).toFixed(2)}% +
+
+
+ +
+
Net Supply APY
+
+ {aprData?.netSupplyApr.times(100).toFixed(2)}% +
+
+
+
+
+
+
@@ -279,7 +383,7 @@ export const LendTable = () => { Card Description - {isPendingMarketConfiguration ? ( + {isPendingMarketConfiguration || isAprPending ? ( SkeletonCardContent ) : ( @@ -331,10 +435,10 @@ export const LendTable = () => {
- {getSupplyApr(supplyRate)} + {aprData?.supplyBaseApr.times(100).toFixed(2)}%
@@ -355,6 +459,31 @@ export const LendTable = () => { }
+
+
Reward APY
+
+
+ {aprData?.supplyRewardApr.times(100).toFixed(2)}% + +
+
+
+
+
Net APY
+
+ {aprData?.netSupplyApr.times(100).toFixed(2)}% +
+
Supply Points diff --git a/apps/frontend/src/components/MarketsView/MarketOverview.tsx b/apps/frontend/src/components/MarketsView/MarketOverview.tsx index 336d8b1d..c28ab8fe 100644 --- a/apps/frontend/src/components/MarketsView/MarketOverview.tsx +++ b/apps/frontend/src/components/MarketsView/MarketOverview.tsx @@ -2,26 +2,23 @@ import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { - useBorrowRate, + useApr, useCollateralConfigurations, useMarketBalanceOfBase, useMarketBasics, useMarketConfiguration, usePrice, - useSupplyRate, useTotalCollateral, useTotalReserves, } from '@/hooks'; -import { ChartData } from '@/lib/charts'; +import type { ChartData } from '@/lib/charts'; import { cn } from '@/lib/utils'; import { SYMBOL_TO_ICON, formatUnits, - getBorrowApr, getFormattedNumber, getFormattedPrice, - getSupplyApr, } from '@/utils'; import BigNumber from 'bignumber.js'; import { ChevronLeft } from 'lucide-react'; @@ -29,6 +26,13 @@ import Link from 'next/link'; import type React from 'react'; import { useMemo } from 'react'; import { IconPair } from '../IconPair'; +import { Line } from '../Line'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '../ui/tooltip'; import { KinkChart } from './KinkChart'; import { MarketChart } from './MarketChart'; import { MarketCollateralsTable } from './MarketCollateralsTable'; @@ -44,15 +48,13 @@ export default function MarketOverview({ baseAsset, chartData, }: MarketOverviewProps) { - const { data: borrowRate } = useBorrowRate(baseAsset); - const { data: supplyRate } = useSupplyRate(baseAsset); const { data: totalReserves } = useTotalReserves(baseAsset); + const { data: aprData, isPending: isAprPending } = useApr(); + const { data: collateralConfigurations } = useCollateralConfigurations(baseAsset); const { data: marketConfiguration } = useMarketConfiguration(baseAsset); - const borrowApr = useMemo(() => getBorrowApr(borrowRate), [borrowRate]); - const supplyApr = useMemo(() => getSupplyApr(supplyRate), [supplyRate]); const { data: availableLiquidity } = useMarketBalanceOfBase(baseAsset); const { data: totalCollateral } = useTotalCollateral(baseAsset); @@ -261,15 +263,115 @@ export default function MarketOverview({
Net Borrow APR
-
- {borrowApr} +
+ + + any }) => + e.preventDefault() + } + > +
+ {aprData?.netBorrowApr.times(100).toFixed(2)}% +
+
+ any; + }) => e.preventDefault()} + > +
+
+ Net Borrow APY +
+
+
+
Borrow APY
+
+ {aprData?.borrowBaseApr.times(100).toFixed(2)}% +
+
+
+
Reward APY
+
+ {aprData?.borrowRewardApr.times(100).toFixed(2)} + % +
+
+
+ +
+
Net Borrow APY
+
+ {aprData?.netBorrowApr.times(100).toFixed(2)}% +
+
+
+
+
+
Net Earn APR
-
- {supplyApr} +
+ + + any }) => + e.preventDefault() + } + > +
+ {aprData?.netSupplyApr.times(100).toFixed(2)}% +
+
+ any; + }) => e.preventDefault()} + > +
+
+ Net Earn APY +
+
+
+
Supply APY
+
+ {aprData?.supplyBaseApr.times(100).toFixed(2)}% +
+
+
+
Reward APY
+
+ {aprData?.supplyRewardApr.times(100).toFixed(2)} + % +
+
+
+ +
+
Net Supply APY
+
+ {aprData?.netSupplyApr.times(100).toFixed(2)}% +
+
+
+
+
+
diff --git a/apps/frontend/src/components/MarketsView/MarketTableRow.tsx b/apps/frontend/src/components/MarketsView/MarketTableRow.tsx index d7881b2f..c7fa0677 100644 --- a/apps/frontend/src/components/MarketsView/MarketTableRow.tsx +++ b/apps/frontend/src/components/MarketsView/MarketTableRow.tsx @@ -2,12 +2,11 @@ import { TableCell, TableRow } from '@/components/ui/table'; import { - useBorrowRate, + useApr, useCollateralConfigurations, useMarketBasics, useMarketConfiguration, usePrice, - useSupplyRate, useTotalCollateral, useUtilization, } from '@/hooks'; @@ -15,21 +14,27 @@ import { SYMBOL_TO_ICON, SYMBOL_TO_NAME, formatUnits, - getBorrowApr, getFormattedPrice, - getSupplyApr, } from '@/utils'; import BigNumber from 'bignumber.js'; import Image from 'next/image'; import type React from 'react'; import { appConfig } from '@/configs'; +import { cn } from '@/lib/utils'; import { useRouter } from 'next/navigation'; import { useMemo } from 'react'; import SWAY from '/public/tokens/sway.svg?url'; import { CircularProgressBar } from '../CircularProgressBar'; import { type Collateral, CollateralIcons } from '../CollateralIcons'; +import { Line } from '../Line'; import { Skeleton } from '../ui/skeleton'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '../ui/tooltip'; const SkeletonRow = ( @@ -69,10 +74,7 @@ export const MarketTableRow = ({ const { data: marketConfiguration } = useMarketConfiguration(); const { data: utilization } = useUtilization(marketName); - const { data: borrowRate } = useBorrowRate(marketName); - const { data: supplyRate } = useSupplyRate(marketName); - const borrowApr = useMemo(() => getBorrowApr(borrowRate), [borrowRate]); - const supplyApr = useMemo(() => getSupplyApr(supplyRate), [supplyRate]); + const { data: aprData, isPending: isAprPending } = useApr(); const { data: collateralConfigurations, @@ -159,11 +161,89 @@ export const MarketTableRow = ({ }
- -
{supplyApr}
+ + + + any }) => e.preventDefault()} + > +
{aprData?.netSupplyApr.times(100).toFixed(2)}%
+
+ any; + }) => e.preventDefault()} + > +
+
+ Net Earn APY +
+
+
+
Supply APY
+
{aprData?.supplyBaseApr.times(100).toFixed(2)}%
+
+
+
Reward APY
+
{aprData?.supplyRewardApr.times(100).toFixed(2)}%
+
+
+ +
+
Net Supply APY
+
{aprData?.netSupplyApr.times(100).toFixed(2)}%
+
+
+
+
+
- -
{borrowApr}
+ + + + any }) => e.preventDefault()} + > +
{aprData?.netBorrowApr.times(100).toFixed(2)}%
+
+ any; + }) => e.preventDefault()} + > +
+
+ Net Borrow APY +
+
+
+
Borrow APY
+
{aprData?.borrowBaseApr.times(100).toFixed(2)}%
+
+
+
Reward APY
+
{aprData?.borrowRewardApr.times(100).toFixed(2)}%
+
+
+ +
+
Net Borrow APY
+
{aprData?.netBorrowApr.times(100).toFixed(2)}%
+
+
+
+
+
{getFormattedPrice( diff --git a/apps/frontend/src/components/PointIcons/PointsTooltip.tsx b/apps/frontend/src/components/PointIcons/PointsTooltip.tsx index 1e0f3b54..ad9878cb 100644 --- a/apps/frontend/src/components/PointIcons/PointsTooltip.tsx +++ b/apps/frontend/src/components/PointIcons/PointsTooltip.tsx @@ -1,4 +1,4 @@ -import { Point } from '@/components/PointIcons'; +import type { Point } from '@/components/PointIcons'; import { SYMBOL_TO_ICON } from '@/utils'; export const POINTS_COLLATERAL: Point[] = [ @@ -156,3 +156,13 @@ export const POINTS_LEND: Point[] = [ displayMultiplier: '3x', }, ]; + +export const POINTS_LM: Point[] = [ + { + id: '1', + name: 'FUEL Token Rewards', + description: <>, + icon: SYMBOL_TO_ICON.FUEL, + displayMultiplier: undefined, + }, +]; diff --git a/apps/frontend/src/components/Providers/FuelProviderWrapper.tsx b/apps/frontend/src/components/Providers/FuelProviderWrapper.tsx index 3a9df643..453a4a8c 100644 --- a/apps/frontend/src/components/Providers/FuelProviderWrapper.tsx +++ b/apps/frontend/src/components/Providers/FuelProviderWrapper.tsx @@ -16,7 +16,7 @@ import { } from '@fuels/connectors'; import { FuelProvider } from '@fuels/react'; import { CHAIN_IDS, type FuelConnector, Provider } from 'fuels'; -import { type ReactNode } from 'react'; +import type { ReactNode } from 'react'; import { fallback } from 'viem'; import { http, createConfig as createConfigWagmiConfig } from 'wagmi'; import { mainnet, sepolia } from 'wagmi/chains'; From 2087606a67e9017287e86e0b2ceb3469badda128 Mon Sep 17 00:00:00 2001 From: martines3000 Date: Mon, 13 Jan 2025 15:38:19 +0100 Subject: [PATCH 4/4] chore: remove old fuel points --- .../AssetsTable/CollateralTable.tsx | 19 +-- .../frontend/src/components/Navbar/Points.tsx | 12 -- .../components/PointIcons/PointsTooltip.tsx | 112 ------------------ apps/frontend/src/hooks/useFuelPoints.ts | 62 ---------- 4 files changed, 2 insertions(+), 203 deletions(-) delete mode 100644 apps/frontend/src/hooks/useFuelPoints.ts diff --git a/apps/frontend/src/components/DashboardView/AssetsTable/CollateralTable.tsx b/apps/frontend/src/components/DashboardView/AssetsTable/CollateralTable.tsx index dfeaf28f..40f7c992 100644 --- a/apps/frontend/src/components/DashboardView/AssetsTable/CollateralTable.tsx +++ b/apps/frontend/src/components/DashboardView/AssetsTable/CollateralTable.tsx @@ -280,14 +280,7 @@ const CollateralTableRow = ({
- +
@@ -402,15 +395,7 @@ const CollateralCard = ({
Supply Points
- +
diff --git a/apps/frontend/src/components/Navbar/Points.tsx b/apps/frontend/src/components/Navbar/Points.tsx index 2534443e..129db120 100644 --- a/apps/frontend/src/components/Navbar/Points.tsx +++ b/apps/frontend/src/components/Navbar/Points.tsx @@ -4,7 +4,6 @@ import { PopoverTrigger, } from '@/components/ui/popover'; import { useUser } from '@/hooks'; -import { useFuelPoints } from '@/hooks/useFuelPoints'; import { cn } from '@/lib/utils'; import { useIsConnected } from '@fuels/react'; import { Trophy } from 'lucide-react'; @@ -26,8 +25,6 @@ export const Points = () => { const { isConnected } = useIsConnected(); - const { data: fuelPoints } = useFuelPoints(); - return ( { {isConnected ? (user ? user.points : '0') : 'Connect Wallet'}
-
-
- Fuel Points - -
- - {isConnected ? fuelPoints : 'Connect Wallet'} - -