diff --git a/.changeset/few-bugs-remember.md b/.changeset/few-bugs-remember.md new file mode 100644 index 000000000..804289954 --- /dev/null +++ b/.changeset/few-bugs-remember.md @@ -0,0 +1,5 @@ +--- +'frontend': patch +--- + +SOV-5278: fix amm rewards estimation diff --git a/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/components/NewPoolStatistics/NewPoolStatistics.tsx b/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/components/NewPoolStatistics/NewPoolStatistics.tsx index 7bb77cc25..814af611a 100644 --- a/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/components/NewPoolStatistics/NewPoolStatistics.tsx +++ b/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/components/NewPoolStatistics/NewPoolStatistics.tsx @@ -100,7 +100,10 @@ export const NewPoolStatistics: FC = ({ const { weeklyRewardsEstimation } = useGetPoolBalanceAndRewards( pool, + newPoolBalanceA, newPoolBalanceB, + isTokenA, + isV2Pool, ); return ( diff --git a/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/hooks/useGetPoolBalanceAndRewards.ts b/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/hooks/useGetPoolBalanceAndRewards.ts index 282660e0f..ca895d121 100644 --- a/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/hooks/useGetPoolBalanceAndRewards.ts +++ b/apps/frontend/src/app/5_pages/MarketMakingPage/components/AdjustAndDepositModal/hooks/useGetPoolBalanceAndRewards.ts @@ -1,57 +1,96 @@ -import { useCallback, useEffect, useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { Decimal } from '@sovryn/utils'; import { RSK_CHAIN_ID } from '../../../../../../config/chains'; import { useGetTokenContract } from '../../../../../../hooks/useGetContract'; -import { COMMON_SYMBOLS } from '../../../../../../utils/asset'; +import { + COMMON_SYMBOLS, + maybeWrappedAsset, +} from '../../../../../../utils/asset'; import { decimalic } from '../../../../../../utils/math'; import { useGetTokenPrice } from '../../../../BorrowPage/hooks/useGetTokenPrice'; +import { useGetReturnRate } from '../../../hooks/useGetReturnRate'; import { AmmLiquidityPool } from '../../../utils/AmmLiquidityPool'; -import { WEEKLY_REWARDS_AMOUNT } from '../AdjustAndDepositModal.constants'; export const useGetPoolBalanceAndRewards = ( pool: AmmLiquidityPool, newPoolBalanceA: Decimal, + newPoolBalanceB: Decimal, + isTokenA: boolean, + isV2Pool: boolean, ) => { - const [weeklyRewardsEstimation, setWeeklyRewardsEstimation] = - useState(Decimal.ZERO); - const poolContract = useGetTokenContract(COMMON_SYMBOLS.WBTC, RSK_CHAIN_ID); - const tokenContract = useGetTokenContract(pool.assetA, RSK_CHAIN_ID); - const { data: tokenPrice } = useGetTokenPrice(tokenContract?.address || ''); + const tokenContractA = useGetTokenContract( + maybeWrappedAsset(pool.assetA), + RSK_CHAIN_ID, + ); + const tokenContractB = useGetTokenContract( + maybeWrappedAsset(pool.assetB), + RSK_CHAIN_ID, + ); + const { data: tokenPriceA } = useGetTokenPrice(tokenContractA?.address || ''); + const { data: tokenPriceB } = useGetTokenPrice(tokenContractB?.address || ''); + const returnRates = useGetReturnRate(pool); - const fetchPoolBalance = useCallback(async () => { - if (!poolContract || !newPoolBalanceA || !tokenPrice || !tokenContract) { - return; - } - try { + const { data: weeklyRewardsEstimation } = useQuery({ + queryKey: [ + 'poolBalanceAndRewards', + pool.converter, + newPoolBalanceA.toString(), + newPoolBalanceB.toString(), + tokenPriceA, + tokenPriceB, + isTokenA, + isV2Pool, + returnRates, + ], + queryFn: async () => { + if ( + !poolContract || + !newPoolBalanceA || + !tokenPriceA || + !tokenContractA + ) { + return Decimal.ZERO; + } const poolBalance = await poolContract .balanceOf(pool.converter) .then(Decimal.fromBigNumberString); if (poolBalance) { - const value = newPoolBalanceA - .div(poolBalance) - .mul(WEEKLY_REWARDS_AMOUNT) - .mul(decimalic(tokenPrice?.token?.lastPriceBtc || '0')); - setWeeklyRewardsEstimation(value); + if (isV2Pool) { + const balance = isTokenA ? newPoolBalanceA : newPoolBalanceB; + return balance + .mul( + decimalic( + isTokenA + ? tokenPriceA.token?.lastPriceBtc || '0' + : tokenPriceB?.token?.lastPriceBtc || '0', + ), + ) + .mul(decimalic(returnRates.beforeRewards).div(100)) + .div(52); + } else { + const value1 = newPoolBalanceA + .mul(decimalic(tokenPriceA?.token?.lastPriceBtc || '0')) + .mul(decimalic(returnRates.beforeRewards).div(100)) + .div(52); + const value2 = newPoolBalanceB + .mul(decimalic(tokenPriceB?.token?.lastPriceBtc || '0')) + .mul(decimalic(returnRates.beforeRewards).div(100)) + .div(52); + return value1.add(value2); + } } - } catch (error) { - console.error('Error fetching pool balance:', error); - } - }, [ - pool.converter, - newPoolBalanceA, - tokenPrice, - poolContract, - tokenContract, - ]); - - useEffect(() => { - fetchPoolBalance(); - }, [fetchPoolBalance]); + + return Decimal.ZERO; + }, + enabled: + !!poolContract && !!newPoolBalanceA && !!tokenPriceA && !!tokenContractA, + initialData: Decimal.ZERO, + }); return { weeklyRewardsEstimation }; }; diff --git a/apps/frontend/src/app/5_pages/MarketMakingPage/components/PoolsTable/components/PoolsTableReturns/PoolsTableReturns.tsx b/apps/frontend/src/app/5_pages/MarketMakingPage/components/PoolsTable/components/PoolsTableReturns/PoolsTableReturns.tsx index b57070290..6f5cdff3e 100644 --- a/apps/frontend/src/app/5_pages/MarketMakingPage/components/PoolsTable/components/PoolsTableReturns/PoolsTableReturns.tsx +++ b/apps/frontend/src/app/5_pages/MarketMakingPage/components/PoolsTable/components/PoolsTableReturns/PoolsTableReturns.tsx @@ -15,7 +15,7 @@ export const PoolsTableReturns: FC = ({ pool, className, }) => { - const { returnRates } = useGetReturnRate(pool); + const returnRates = useGetReturnRate(pool); const returnRate = useMemo( () => diff --git a/apps/frontend/src/app/5_pages/MarketMakingPage/hooks/useGetReturnRate.ts b/apps/frontend/src/app/5_pages/MarketMakingPage/hooks/useGetReturnRate.ts index 035c7bbb9..2c3a27a48 100644 --- a/apps/frontend/src/app/5_pages/MarketMakingPage/hooks/useGetReturnRate.ts +++ b/apps/frontend/src/app/5_pages/MarketMakingPage/hooks/useGetReturnRate.ts @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { useBlockNumber } from '../../../../hooks/useBlockNumber'; import { getAmmServiceUrl } from '../../../../utils/helpers'; @@ -32,53 +32,44 @@ export const useGetReturnRate = ({ const ammServiceUrl = getAmmServiceUrl(); const { value: block } = useBlockNumber(); - const [returnRates, setReturnRates] = useState({ - beforeRewards: '0', - afterRewards: '0', - }); - - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch(`${ammServiceUrl}/amm`); - const data: AmmResponse = await response.json(); + const { data } = useQuery({ + queryKey: ['ammPoolReturnRates', converter, block], + queryFn: async () => { + const response = await fetch(`${ammServiceUrl}/amm`); + const data: AmmResponse = await response.json(); - if (data[converter]) { - const poolData = - converterVersion === 1 - ? data[converter].data[Object.keys(data[converter].data)[0]] - : data[converter].data[poolTokenA]; + if (data[converter]) { + const poolData = + converterVersion === 1 + ? data[converter].data[Object.keys(data[converter].data)[0]] + : data[converter].data[poolTokenA]; - if (poolData && poolData.length > 0) { - const sumFeesApy = poolData.reduce( - (acc, entry) => acc + parseFloat(entry.APY_fees_pc), - 0, - ); - const sumTotalApy = poolData.reduce( - (acc, entry) => acc + parseFloat(entry.APY_pc), - 0, - ); + if (poolData && poolData.length > 0) { + const sumFeesApy = poolData.reduce( + (acc, entry) => acc + parseFloat(entry.APY_fees_pc), + 0, + ); + const sumTotalApy = poolData.reduce( + (acc, entry) => acc + parseFloat(entry.APY_pc), + 0, + ); - const avgFeesApy = (sumFeesApy / poolData.length).toFixed(2); - const avgTotalApy = (sumTotalApy / poolData.length).toFixed(2); + const avgFeesApy = (sumFeesApy / poolData.length).toFixed(2); + const avgTotalApy = (sumTotalApy / poolData.length).toFixed(2); - setReturnRates({ - beforeRewards: avgFeesApy, - afterRewards: avgTotalApy, - }); - } else { - setReturnRates({ beforeRewards: '0', afterRewards: '0' }); - } + return { + beforeRewards: avgFeesApy, + afterRewards: avgTotalApy, + }; } else { - setReturnRates({ beforeRewards: '0', afterRewards: '0' }); + return { beforeRewards: '0', afterRewards: '0' }; } - } catch (error) { - console.error('Error fetching amm pool data:', error); + } else { + return { beforeRewards: '0', afterRewards: '0' }; } - }; - - fetchData(); - }, [ammServiceUrl, block, converter, converterVersion, poolTokenA]); + }, + initialData: { beforeRewards: '0', afterRewards: '0' }, + }); - return { returnRates }; + return data; }; diff --git a/apps/frontend/src/utils/graphql/rsk/generated.tsx b/apps/frontend/src/utils/graphql/rsk/generated.tsx index 1679b3971..0ee00dec7 100644 --- a/apps/frontend/src/utils/graphql/rsk/generated.tsx +++ b/apps/frontend/src/utils/graphql/rsk/generated.tsx @@ -16669,6 +16669,7 @@ export type GetTokenQuery = { __typename?: 'Query'; token?: { __typename?: 'Token'; + symbol?: string | null; lastPriceUsd: string; lastPriceBtc: string; } | null; @@ -19108,6 +19109,7 @@ export type GetSwapHistoryQueryResult = Apollo.QueryResult< export const GetTokenDocument = gql` query getToken($id: ID!) { token(id: $id) { + symbol lastPriceUsd lastPriceBtc } diff --git a/apps/frontend/src/utils/graphql/rsk/operations/getToken.graphql b/apps/frontend/src/utils/graphql/rsk/operations/getToken.graphql index 3984ae8d5..f4ce928d6 100644 --- a/apps/frontend/src/utils/graphql/rsk/operations/getToken.graphql +++ b/apps/frontend/src/utils/graphql/rsk/operations/getToken.graphql @@ -1,5 +1,6 @@ query getToken($id: ID!) { token(id: $id) { + symbol lastPriceUsd lastPriceBtc }