From 94e57c7f5e7a2de7f08ea732b84327c95f04dec1 Mon Sep 17 00:00:00 2001 From: viet-nv Date: Mon, 24 Jul 2023 18:11:28 +0700 Subject: [PATCH] feat: multiple farm v2 contracts --- src/pages/Farm/ElasticFarmCombination.tsx | 25 +- .../ElasticFarmv2/components/FarmCard.tsx | 4 +- .../ElasticFarmv2/components/ListView.tsx | 4 +- .../components/StakeWithNFTsModal.tsx | 4 +- .../components/UnstakeWithNFTsModal.tsx | 7 +- .../components/UpdateLiquidityModal.tsx | 6 +- src/pages/Farm/ElasticFarmv2/index.tsx | 20 +- src/state/farms/elasticv2/hooks.ts | 29 ++- src/state/farms/elasticv2/types.ts | 2 + src/state/farms/elasticv2/updater.tsx | 245 +++++++++--------- 10 files changed, 197 insertions(+), 149 deletions(-) diff --git a/src/pages/Farm/ElasticFarmCombination.tsx b/src/pages/Farm/ElasticFarmCombination.tsx index 9b2c970e68..a37c27a6d9 100644 --- a/src/pages/Farm/ElasticFarmCombination.tsx +++ b/src/pages/Farm/ElasticFarmCombination.tsx @@ -1,5 +1,5 @@ import { Trans } from '@lingui/macro' -import { FC, useEffect, useState } from 'react' +import { FC, useEffect, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' import { Flex, Text } from 'rebass' @@ -12,6 +12,7 @@ import { ApplicationModal } from 'state/application/actions' import { useModalOpen, useOpenModal } from 'state/application/hooks' import { useFilteredFarms } from 'state/farms/elastic/hooks' import { useFilteredFarmsV2 } from 'state/farms/elasticv2/hooks' +import { ElasticFarmV2 } from 'state/farms/elasticv2/types' import ElasticFarmv2 from './ElasticFarmv2' @@ -20,6 +21,18 @@ export const ElasticFarmCombination: FC = () => { const { filteredFarms: filteredFarmsV1, loading: loadingV1 } = useFilteredFarms() const { filteredFarms: filteredFarmsV2, loading: loadingV2 } = useFilteredFarmsV2() + const farmByContract = useMemo(() => { + return filteredFarmsV2?.reduce((acc, cur) => { + if (acc[cur.farmAddress]) { + acc[cur.farmAddress].push(cur) + } else { + acc[cur.farmAddress] = [cur] + } + + return acc + }, {} as { [address: string]: ElasticFarmV2[] }) + }, [filteredFarmsV2]) + const [searchParams] = useSearchParams() const search: string = searchParams.get('search')?.toLowerCase() || '' @@ -75,7 +88,15 @@ export const ElasticFarmCombination: FC = () => { setShowFarmStepGuide('v1')} noStaticFarm={!filteredFarmsV2.length} /> {!!filteredFarmsV1.length && !!filteredFarmsV2.length && } - setShowFarmStepGuide('v2')} noDynamicFarm={!filteredFarmsV1.length} /> + + {Object.keys(farmByContract).map(contract => ( + setShowFarmStepGuide('v2')} + noDynamicFarm={!filteredFarmsV1.length} + farmAddress={contract} + key={contract} + /> + ))} ) } diff --git a/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx b/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx index bf6955b093..8e9e2006e0 100644 --- a/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx @@ -113,7 +113,7 @@ function FarmCard({ const [, setSharePoolAddress] = useShareFarmAddress() const currentTimestamp = Math.floor(Date.now() / 1000) - const stakedPos = useUserFarmV2Info(farm.fId) + const stakedPos = useUserFarmV2Info(farm.farmAddress, farm.fId) let amountToken0 = CurrencyAmount.fromRawAmount(farm.token0.wrapped, 0) let amountToken1 = CurrencyAmount.fromRawAmount(farm.token1.wrapped, 0) @@ -162,7 +162,7 @@ function FarmCard({ setAttemptingTxn(false) } - const { harvest } = useFarmV2Action() + const { harvest } = useFarmV2Action(farm.farmAddress) const handleHarvest = useCallback(() => { setShowConfirmModal(true) diff --git a/src/pages/Farm/ElasticFarmv2/components/ListView.tsx b/src/pages/Farm/ElasticFarmv2/components/ListView.tsx index 6ecc91acf8..58913087ee 100644 --- a/src/pages/Farm/ElasticFarmv2/components/ListView.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/ListView.tsx @@ -68,7 +68,7 @@ export const ListView = ({ const [, setSharePoolAddress] = useShareFarmAddress() const currentTimestamp = Math.floor(Date.now() / 1000) - const stakedPos = useUserFarmV2Info(farm.fId) + const stakedPos = useUserFarmV2Info(farm.farmAddress, farm.fId) let amountToken0 = CurrencyAmount.fromRawAmount(farm.token0.wrapped, 0) let amountToken1 = CurrencyAmount.fromRawAmount(farm.token1.wrapped, 0) @@ -116,7 +116,7 @@ export const ListView = ({ setAttemptingTxn(false) } - const { harvest } = useFarmV2Action() + const { harvest } = useFarmV2Action(farm.farmAddress) const handleHarvest = useCallback(() => { setShowConfirmModal(true) diff --git a/src/pages/Farm/ElasticFarmv2/components/StakeWithNFTsModal.tsx b/src/pages/Farm/ElasticFarmv2/components/StakeWithNFTsModal.tsx index 0c7f3ca046..645fa4742c 100644 --- a/src/pages/Farm/ElasticFarmv2/components/StakeWithNFTsModal.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/StakeWithNFTsModal.tsx @@ -211,10 +211,12 @@ const StakeWithNFTsModal = ({ isOpen, onDismiss, farm, + farmAddress, }: { farm: ElasticFarmV2 isOpen: boolean onDismiss: () => void + farmAddress: string }) => { const [activeRange, setActiveRange] = useState(farm.ranges.filter(item => !item.isRemoved)[0]) @@ -252,7 +254,7 @@ const StakeWithNFTsModal = ({ }) mixpanel.track('ElasticFarmV2 - StakeModal - NFT Clicked', { nftId: tokenId }) }, []) - const { deposit } = useFarmV2Action() + const { deposit } = useFarmV2Action(farmAddress) const [showConfirmModal, setShowConfirmModal] = useState(false) const [txHash, setTxHash] = useState('') diff --git a/src/pages/Farm/ElasticFarmv2/components/UnstakeWithNFTsModal.tsx b/src/pages/Farm/ElasticFarmv2/components/UnstakeWithNFTsModal.tsx index d43f81de3d..c1235a05ff 100644 --- a/src/pages/Farm/ElasticFarmv2/components/UnstakeWithNFTsModal.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/UnstakeWithNFTsModal.tsx @@ -104,7 +104,6 @@ const NFTItem = ({ pos: UserFarmV2Info onClick?: (tokenId: string) => void }) => { - console.log(pos.nftId.toString(), pos.unclaimedRewardsUsd) const priceLower = getTickToPrice( pos.position.pool.token0.wrapped, pos.position.pool.token1.wrapped, @@ -250,12 +249,14 @@ const UnstakeWithNFTsModal = ({ isOpen, onDismiss, farm, + farmAddress, }: { isOpen: boolean onDismiss: () => void farm: ElasticFarmV2 + farmAddress: string }) => { - const stakedPos = useUserFarmV2Info(farm.fId) + const stakedPos = useUserFarmV2Info(farmAddress, farm.fId) const theme = useTheme() const [selectedPos, setSelectedPos] = useState<{ [tokenId: string]: boolean }>({}) @@ -278,7 +279,7 @@ const UnstakeWithNFTsModal = ({ mixpanel.track('ElasticFarmV2 - Unstake Modal - NFT Clicked', { nftId: tokenId }) }, []) - const { withdraw } = useFarmV2Action() + const { withdraw } = useFarmV2Action(farmAddress) const [showConfirmModal, setShowConfirmModal] = useState(false) const [txHash, setTxHash] = useState('') diff --git a/src/pages/Farm/ElasticFarmv2/components/UpdateLiquidityModal.tsx b/src/pages/Farm/ElasticFarmv2/components/UpdateLiquidityModal.tsx index 344dff79a0..0e545bfc77 100644 --- a/src/pages/Farm/ElasticFarmv2/components/UpdateLiquidityModal.tsx +++ b/src/pages/Farm/ElasticFarmv2/components/UpdateLiquidityModal.tsx @@ -252,12 +252,14 @@ const UpdateLiquidityModal = ({ isOpen, onDismiss, farm, + farmAddress, }: { isOpen: boolean onDismiss: () => void farm: ElasticFarmV2 + farmAddress: string }) => { - const stakedPos = useUserFarmV2Info(farm.fId) + const stakedPos = useUserFarmV2Info(farmAddress, farm.fId) const allEligiblePositions = stakedPos.filter(item => { const range = farm.ranges.find(r => r.index === item.rangeId) @@ -287,7 +289,7 @@ const UpdateLiquidityModal = ({ mixpanel.track('ElasticFarmV2 - Update Liquidity Modal - NFT Clicked', { nftId: tokenId }) }, []) - const { updateLiquidity } = useFarmV2Action() + const { updateLiquidity } = useFarmV2Action(farmAddress) const [showConfirmModal, setShowConfirmModal] = useState(false) const [txHash, setTxHash] = useState('') diff --git a/src/pages/Farm/ElasticFarmv2/index.tsx b/src/pages/Farm/ElasticFarmv2/index.tsx index 78daf7114a..2de2870166 100644 --- a/src/pages/Farm/ElasticFarmv2/index.tsx +++ b/src/pages/Farm/ElasticFarmv2/index.tsx @@ -20,8 +20,6 @@ import { MouseoverTooltip, MouseoverTooltipDesktopOnly, TextDashed } from 'compo import { ConnectWalletButton } from 'components/YieldPools/ElasticFarmGroup/buttons' import { FarmList } from 'components/YieldPools/ElasticFarmGroup/styleds' import { ClickableText, ElasticFarmV2TableHeader } from 'components/YieldPools/styleds' -import { NETWORKS_INFO } from 'constants/networks' -import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React } from 'hooks' import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' import useTheme from 'hooks/useTheme' @@ -68,13 +66,14 @@ const Wrapper = styled.div<{ noDynamicFarm?: boolean }>` export default function ElasticFarmv2({ onShowStepGuide, noDynamicFarm, + farmAddress, }: { onShowStepGuide: () => void noDynamicFarm: boolean + farmAddress: string }) { const theme = useTheme() - const { chainId, account } = useActiveWeb3React() - const farmAddress = (NETWORKS_INFO[chainId] as EVMNetworkInfo).elastic?.farmV2Contract + const { account } = useActiveWeb3React() const above1000 = useMedia('(min-width: 1000px)') const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`) @@ -83,7 +82,7 @@ export default function ElasticFarmv2({ const sortField = searchParams.get('orderBy') || SORT_FIELD.MY_DEPOSIT const sortDirection = searchParams.get('orderDirection') || SORT_DIRECTION.DESC - const { filteredFarms, farms, updatedFarms, userInfo } = useFilteredFarmsV2() + const { filteredFarms, farms, updatedFarms, userInfo } = useFilteredFarmsV2(farmAddress) const depositedUsd = userInfo?.reduce((acc, cur) => acc + cur.positionUsdValue, 0) || 0 const depositedTokenAmounts: { [address: string]: CurrencyAmount } = {} @@ -97,7 +96,7 @@ export default function ElasticFarmv2({ else depositedTokenAmounts[address1] = depositedTokenAmounts[address1].add(item.position.amount1) }) - const { approve } = useFarmV2Action() + const { approve } = useFarmV2Action(farmAddress) const posManager = useProAmmNFTPositionManagerContract() const [approvalTx, setApprovalTx] = useState('') const isApprovalTxPending = useIsTransactionPending(approvalTx) @@ -408,13 +407,19 @@ export default function ElasticFarmv2({ {!!selectedFarm && ( - setSelectedFarm(null)} /> + setSelectedFarm(null)} + farmAddress={farmAddress} + /> )} {!!selectedUnstakeFarm && ( setSelectedUnstakeFarm(null)} + farmAddress={farmAddress} /> )} {!!selectedUpdateFarm && ( @@ -422,6 +427,7 @@ export default function ElasticFarmv2({ farm={selectedUpdateFarm} isOpen={!!selectedUpdateFarm} onDismiss={() => setSelectedUpdateFarm(null)} + farmAddress={farmAddress} /> )} diff --git a/src/state/farms/elasticv2/hooks.ts b/src/state/farms/elasticv2/hooks.ts index 8c9a2946ba..c27c1a3fa6 100644 --- a/src/state/farms/elasticv2/hooks.ts +++ b/src/state/farms/elasticv2/hooks.ts @@ -5,8 +5,6 @@ import { useLocalStorage } from 'react-use' import FarmV2ABI from 'constants/abis/v2/farmv2.json' import { ELASTIC_FARM_TYPE, FARM_TAB } from 'constants/index' import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages' -import { NETWORKS_INFO } from 'constants/networks' -import { EVMNetworkInfo } from 'constants/networks/type' import { useActiveWeb3React } from 'hooks' import { useContract, useProAmmNFTPositionManagerContract } from 'hooks/useContract' import { useAppSelector } from 'state/hooks' @@ -23,9 +21,12 @@ export const useElasticFarmsV2 = () => { return elasticFarm || {} } -export const useUserFarmV2Info = (fId: number): UserFarmV2Info[] => { +export const useUserFarmV2Info = (farmAddress: string, fId: number): UserFarmV2Info[] => { const { userInfo } = useElasticFarmsV2() - return useMemo(() => userInfo?.filter(item => item.fId === fId) || [], [fId, userInfo]) + return useMemo( + () => userInfo?.filter(item => item.fId === fId && item.farmAddress === farmAddress) || [], + [fId, userInfo, farmAddress], + ) } export enum SORT_FIELD { @@ -42,7 +43,7 @@ export enum SORT_DIRECTION { DESC = 'desc', } -export const useFilteredFarmsV2 = () => { +export const useFilteredFarmsV2 = (farmAddress?: string) => { const { isEVM, chainId } = useActiveWeb3React() const [searchParams] = useSearchParams() @@ -101,6 +102,8 @@ export const useFilteredFarmsV2 = () => { : farm.endTime < now || farm.isSettled, ) + if (farmAddress) result = result?.filter(item => item.farmAddress === farmAddress) + // Filter by search value const searchAddress = isAddressString(chainId, search) if (searchAddress) { @@ -188,6 +191,7 @@ export const useFilteredFarmsV2 = () => { isEVM, search, elasticType, + farmAddress, ]) return { @@ -199,19 +203,18 @@ export const useFilteredFarmsV2 = () => { } } -export const useFarmV2Action = () => { - const { chainId, account } = useActiveWeb3React() - const address = (NETWORKS_INFO[chainId] as EVMNetworkInfo).elastic?.farmV2Contract +export const useFarmV2Action = (farmAddress: string) => { + const { account } = useActiveWeb3React() const addTransactionWithType = useTransactionAdder() - const farmContract = useContract(address, FarmV2ABI) + const farmContract = useContract(farmAddress, FarmV2ABI) const posManager = useProAmmNFTPositionManagerContract() const approve = useCallback(async () => { if (!posManager) { throw new Error(CONTRACT_NOT_FOUND_MSG) } - const estimateGas = await posManager.estimateGas.setApprovalForAll(address, true) - const tx = await posManager.setApprovalForAll(address, true, { + const estimateGas = await posManager.estimateGas.setApprovalForAll(farmAddress, true) + const tx = await posManager.setApprovalForAll(farmAddress, true, { gasLimit: calculateGasMargin(estimateGas), }) addTransactionWithType({ @@ -219,11 +222,11 @@ export const useFarmV2Action = () => { type: TRANSACTION_TYPE.APPROVE, extraInfo: { summary: `Elastic Static Farm`, - contract: address, + contract: farmAddress, }, }) return tx.hash - }, [posManager, address, addTransactionWithType]) + }, [posManager, farmAddress, addTransactionWithType]) //Deposit const deposit = useCallback( diff --git a/src/state/farms/elasticv2/types.ts b/src/state/farms/elasticv2/types.ts index 81101758de..7ee3b293ea 100644 --- a/src/state/farms/elasticv2/types.ts +++ b/src/state/farms/elasticv2/types.ts @@ -18,6 +18,7 @@ export interface ElasticFarmV2Range { export interface ElasticFarmV2 { id: string fId: number + farmAddress: string startTime: number endTime: number isSettled: boolean @@ -33,6 +34,7 @@ export interface ElasticFarmV2 { } export interface UserFarmV2Info { + farmAddress: string poolAddress: string nftId: BigNumber position: Position diff --git a/src/state/farms/elasticv2/updater.tsx b/src/state/farms/elasticv2/updater.tsx index cdbf6f81b9..4b8ac534da 100644 --- a/src/state/farms/elasticv2/updater.tsx +++ b/src/state/farms/elasticv2/updater.tsx @@ -216,6 +216,7 @@ export default function ElasticFarmV2Updater({ interval = true }: { interval?: b return { id: farm.id, fId: +farm.id.split('_')[1], + farmAddress: farm.id.split('_')[0], startTime: Number(farm.startTime), endTime: Number(farm.endTime), isSettled: farm.isSettled, @@ -275,134 +276,144 @@ export default function ElasticFarmV2Updater({ interval = true }: { interval?: b dispatch(setFarms({ chainId, farms: formattedData })) - const farmAddress = (networkInfo as EVMNetworkInfo)?.elastic?.farmV2Contract + const farmAddresses = [...new Set(formattedData.map(item => item.farmAddress))] + + type UserInfoRes = { + nftId: BigNumber + fId: BigNumber + rangeId: BigNumber + liquidity: BigNumber + currentUnclaimedRewards: BigNumber[] + } + + let userFarmInfos: UserFarmV2Info[] = [] // get user deposit info - if (account && farmv2QuoterContract && multicallContract && farmAddress) { - farmv2QuoterContract.getUserInfo(farmAddress, account).then( - async ( - res: { - nftId: BigNumber - fId: BigNumber - rangeId: BigNumber - liquidity: BigNumber - currentUnclaimedRewards: BigNumber[] - }[], - ) => { - const nftIds = res.map(item => { - return item.nftId - }) - const nftDetailFragment = positionManagerInterface.getFunction('positions') - const nftDetailChunks = nftIds.map(id => ({ - target: (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager, - callData: positionManagerInterface.encodeFunctionData(nftDetailFragment, [id]), - })) - - const detailNFTMultiCallData = ( - await multicallContract.callStatic.tryBlockAndAggregate(false, nftDetailChunks) - ).returnData - - const nftDetailResult = detailNFTMultiCallData.map((data: [boolean, string]) => - data[0] ? positionManagerInterface.decodeFunctionResult(nftDetailFragment, data[1]) : null, - ) + if (account && farmv2QuoterContract && multicallContract && farmAddresses.length) { + const userInfos: UserInfoRes[][] = await Promise.all( + farmAddresses.map(farmAddress => { + return farmv2QuoterContract.getUserInfo(farmAddress, account) + }), + ) - type NFT_INFO = { - [id: string]: { - poolAddress: string - liquidity: BigNumber - tickLower: BigNumber - tickUpper: BigNumber - } + userInfos.forEach(async (res: UserInfoRes[], index) => { + const nftIds = res.map(item => { + return item.nftId + }) + const nftDetailFragment = positionManagerInterface.getFunction('positions') + const nftDetailChunks = nftIds.map(id => ({ + target: (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager, + callData: positionManagerInterface.encodeFunctionData(nftDetailFragment, [id]), + })) + + const detailNFTMultiCallData = ( + await multicallContract.callStatic.tryBlockAndAggregate(false, nftDetailChunks) + ).returnData + + const nftDetailResult = detailNFTMultiCallData.map((data: [boolean, string]) => + data[0] ? positionManagerInterface.decodeFunctionResult(nftDetailFragment, data[1]) : null, + ) + + type NFT_INFO = { + [id: string]: { + poolAddress: string + liquidity: BigNumber + tickLower: BigNumber + tickUpper: BigNumber } - const nftInfos = nftDetailResult.reduce((acc: NFT_INFO, item: any, index: number) => { - if (!item) return acc - return { - ...acc, - [nftIds[index].toString()]: { - poolAddress: getCreate2Address( - (networkInfo as EVMNetworkInfo).elastic.coreFactory, - keccak256( - ['bytes'], - [ - defaultAbiCoder.encode( - ['address', 'address', 'uint24'], - [item.info.token0, item.info.token1, item.info.fee], - ), - ], - ), - (networkInfo as EVMNetworkInfo).elastic.initCodeHash, + } + + const nftInfos = nftDetailResult.reduce((acc: NFT_INFO, item: any, index: number) => { + if (!item) return acc + return { + ...acc, + [nftIds[index].toString()]: { + poolAddress: getCreate2Address( + (networkInfo as EVMNetworkInfo).elastic.coreFactory, + keccak256( + ['bytes'], + [ + defaultAbiCoder.encode( + ['address', 'address', 'uint24'], + [item.info.token0, item.info.token1, item.info.fee], + ), + ], ), - liquidity: item.pos.liquidity, - tickLower: item.pos.tickLower, - tickUpper: item.pos.tickUpper, - }, - } - }, {} as NFT_INFO) - - const infos = res.reduce((acc: UserFarmV2Info[], item) => { - const farm = formattedData.find( - farm => - farm.poolAddress.toLowerCase() === nftInfos[item.nftId.toString()].poolAddress.toLowerCase() && - +farm.fId === +item.fId.toString(), - ) - if (!farm) return acc + (networkInfo as EVMNetworkInfo).elastic.initCodeHash, + ), + liquidity: item.pos.liquidity, + tickLower: item.pos.tickLower, + tickUpper: item.pos.tickUpper, + }, + } + }, {} as NFT_INFO) - const position = new Position({ - pool: farm.pool, - liquidity: nftInfos[item.nftId.toString()].liquidity, - tickLower: nftInfos[item.nftId.toString()].tickLower, - tickUpper: nftInfos[item.nftId.toString()].tickUpper, - }) - const positionUsdValue = - +position.amount0.toExact() * (prices[position.amount0.currency.wrapped.address] || 0) + - +position.amount1.toExact() * (prices[position.amount1.currency.wrapped.address] || 0) - - const stakedLiquidity = BigNumber.from(item.liquidity.toString()).div( - farm.ranges.find(r => r.index.toString() === item.rangeId.toString())?.weight || 1, - ) + const infos = res.reduce((acc: UserFarmV2Info[], item) => { + const farm = formattedData.find( + farm => + farm.poolAddress.toLowerCase() === nftInfos[item.nftId.toString()].poolAddress.toLowerCase() && + +farm.fId === +item.fId.toString(), + ) + if (!farm) return acc - const stakedPos = new Position({ - pool: farm.pool, - liquidity: stakedLiquidity.toString(), - tickLower: nftInfos[item.nftId.toString()].tickLower, - tickUpper: nftInfos[item.nftId.toString()].tickUpper, - }) + const position = new Position({ + pool: farm.pool, + liquidity: nftInfos[item.nftId.toString()].liquidity, + tickLower: nftInfos[item.nftId.toString()].tickLower, + tickUpper: nftInfos[item.nftId.toString()].tickUpper, + }) + const positionUsdValue = + +position.amount0.toExact() * (prices[position.amount0.currency.wrapped.address] || 0) + + +position.amount1.toExact() * (prices[position.amount1.currency.wrapped.address] || 0) - const stakedUsdValue = - +stakedPos.amount0.toExact() * (prices[stakedPos.amount0.currency.wrapped.address] || 0) + - +stakedPos.amount1.toExact() * (prices[stakedPos.amount1.currency.wrapped.address] || 0) + const stakedLiquidity = BigNumber.from(item.liquidity.toString()).div( + farm.ranges.find(r => r.index.toString() === item.rangeId.toString())?.weight || 1, + ) - const unclaimedRewards = farm.totalRewards.map((rw, i) => - CurrencyAmount.fromRawAmount(rw.currency, item.currentUnclaimedRewards[i].toString()), - ) + const stakedPos = new Position({ + pool: farm.pool, + liquidity: stakedLiquidity.toString(), + tickLower: nftInfos[item.nftId.toString()].tickLower, + tickUpper: nftInfos[item.nftId.toString()].tickUpper, + }) - const unclaimedRewardsUsd = unclaimedRewards.reduce( - (total, item) => total + +item.toExact() * (prices[item.currency.wrapped.address] || 0), - 0, - ) + const stakedUsdValue = + +stakedPos.amount0.toExact() * (prices[stakedPos.amount0.currency.wrapped.address] || 0) + + +stakedPos.amount1.toExact() * (prices[stakedPos.amount1.currency.wrapped.address] || 0) - return [ - ...acc, - { - nftId: item.nftId, - position, - stakedPosition: stakedPos, - liquidity: nftInfos[item.nftId.toString()].liquidity, - stakedLiquidity: stakedLiquidity, - poolAddress: farm.poolAddress, - fId: Number(item.fId.toString()), - rangeId: Number(item.rangeId.toString()), - unclaimedRewards, - positionUsdValue, - stakedUsdValue, - unclaimedRewardsUsd, - }, - ] - }, [] as UserFarmV2Info[]) - - dispatch(setUserFarmInfo({ chainId, userInfo: infos })) - }, - ) + const unclaimedRewards = farm.totalRewards.map((rw, i) => + CurrencyAmount.fromRawAmount(rw.currency, item.currentUnclaimedRewards[i].toString()), + ) + + const unclaimedRewardsUsd = unclaimedRewards.reduce( + (total, item) => total + +item.toExact() * (prices[item.currency.wrapped.address] || 0), + 0, + ) + + return [ + ...acc, + { + nftId: item.nftId, + position, + stakedPosition: stakedPos, + liquidity: nftInfos[item.nftId.toString()].liquidity, + stakedLiquidity: stakedLiquidity, + poolAddress: farm.poolAddress, + fId: Number(item.fId.toString()), + rangeId: Number(item.rangeId.toString()), + unclaimedRewards, + positionUsdValue, + stakedUsdValue, + unclaimedRewardsUsd, + farmAddress: farmAddresses[index], + }, + ] + }, [] as UserFarmV2Info[]) + + userFarmInfos = userFarmInfos.concat(infos) + }) + + dispatch(setUserFarmInfo({ chainId, userInfo: userFarmInfos })) } else { dispatch(setUserFarmInfo({ chainId, userInfo: [] })) }