Skip to content

Commit

Permalink
feat: farm config migrate (#10588)
Browse files Browse the repository at this point in the history
<!--
Before opening a pull request, please read the [contributing
guidelines](https://github.com/pancakeswap/pancake-frontend/blob/develop/CONTRIBUTING.md)
first
-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR updates deprecated farm configurations and refactors legacy farm
configs to use a new structure.

### Detailed summary
- Deprecated farm configurations updated for various chains
- Refactored legacy farm configs to use a new structure
- Updated functions and imports to align with the changes

> The following files were skipped due to too many changes:
`apps/web/src/views/Swap/hooks/useTradingRewardTokenList.tsx`,
`packages/farms/src/farms/zkSync.ts`, `packages/farms/scripts/build.ts`,
`packages/farms/src/farms/polygonZkEVM.ts`,
`packages/farms/src/farms/zkSyncTestnet.ts`,
`apps/web/src/state/farmsV4/state/farmPools/fetcher.ts`,
`packages/farms/src/farms/polygonZkEVMTestnet.ts`,
`apps/web/src/pages/api/v3/[chainId]/farms/index.ts`,
`packages/farms/src/farms/index.ts`,
`apps/web/src/state/farmsV3/hooks.ts`,
`apps/web/src/state/pools/hooks.ts`, `apps/web/src/hooks/useFarm.ts`,
`packages/farms/src/farms/opBNBTestnet.ts`,
`apps/web/src/views/Info/Pools/PoolPage.tsx`,
`apps/web/src/views/universalFarms/hooks/useCakeEarning.ts`,
`packages/farms/src/farms/arb.ts`, `packages/farms/src/types.ts`,
`packages/farms/src/defineFarmV3Configs.ts`,
`apps/web/src/views/Home/components/Banners/hooks/useIsRenderUserBanner.ts`,
`apps/web/src/views/universalFarms/hooks/useV2FarmActions.ts`,
`apps/web/src/state/farmsV4/state/extendPools/fetcher.ts`,
`apps/web/src/views/universalFarms/components/PositionItem/StablePositionItem.tsx`,
`apps/web/src/views/universalFarms/PoolsPage.tsx`,
`apps/web/src/views/PoolDetail/components/MyPositions.tsx`,
`apps/web/src/views/universalFarms/components/PositionItem/V2PositionItem.tsx`,
`apps/web/src/views/universalFarms/components/PoolAprButton/V2PoolAprModal.tsx`,
`packages/farms/src/utils.ts`,
`packages/farms/src/getLegacyFarmConfig.test.ts`,
`packages/farms/src/getLegacyFarmConfig.ts`,
`apps/web/src/views/Home/hooks/useFarmsWithBalance.tsx`,
`apps/web/src/state/farms/hooks.ts`, `packages/farms/src/farms/eth.ts`,
`packages/farms/constants/v3/index.ts`,
`apps/web/src/views/TradingReward/config/pairs/index.tsx`,
`apps/web/src/state/farmsV4/state/poolApr/fetcher.ts`,
`apps/web/src/state/farmsV4/state/accountPositions/fetcher.ts`,
`apps/web/src/state/farms/index.ts`,
`apps/web/src/state/farmsV4/state/farmPools/hooks.ts`,
`packages/farms/src/farms/bscTestnet.ts`,
`apps/web/src/views/universalFarms/components/PositionActions/V2PositionActions.tsx`,
`packages/farms/src/farms/index.test.ts`,
`packages/farms/src/farms/bsc.ts`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your
question}`

<!-- end pr-codex -->
  • Loading branch information
ChefJerry authored Sep 2, 2024
1 parent f128e2d commit a6be81d
Show file tree
Hide file tree
Showing 73 changed files with 2,079 additions and 569 deletions.
8 changes: 4 additions & 4 deletions apps/web/src/hooks/useFarm.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createFarmFetcherV3, ComputedFarmConfigV3, fetchTokenUSDValues } from '@pancakeswap/farms'
import { farmsV3ConfigChainMap } from '@pancakeswap/farms/constants/v3'
import { ComputedFarmConfigV3, createFarmFetcherV3, fetchTokenUSDValues } from '@pancakeswap/farms'
import { priceHelperTokens } from '@pancakeswap/farms/constants/common'
import { Currency, ERC20Token } from '@pancakeswap/sdk'
import { FeeAmount, Pool } from '@pancakeswap/v3-sdk'
import { useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import { useMemo } from 'react'

import { legacyFarmsV3ConfigChainMap } from '@pancakeswap/farms/constants/v3'
import { FAST_INTERVAL } from 'config/constants'
import { getViemClients } from 'utils/viem'

Expand All @@ -23,7 +23,7 @@ export function useFarm({ currencyA, currencyB, feeAmount }: FarmParams) {
if (!chainId || !currencyA || !currencyB || !feeAmount) {
return null
}
const farms: ComputedFarmConfigV3[] = farmsV3ConfigChainMap[chainId]
const farms: ComputedFarmConfigV3[] = legacyFarmsV3ConfigChainMap[chainId]
if (!farms) {
return null
}
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/pages/api/v3/[chainId]/farms/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChainId } from '@pancakeswap/chains'
import { createFarmFetcherV3, fetchCommonTokenUSDValue } from '@pancakeswap/farms'
import { priceHelperTokens } from '@pancakeswap/farms/constants/common'
import { farmsV3ConfigChainMap } from '@pancakeswap/farms/constants/v3'
import { ChainId } from '@pancakeswap/chains'
import { legacyFarmsV3ConfigChainMap } from '@pancakeswap/farms/constants/v3'
import { NextApiHandler } from 'next'
import { getViemClients } from 'utils/viem.server'
import { nativeEnum as zNativeEnum } from 'zod'
Expand All @@ -22,7 +22,7 @@ const handler: NextApiHandler = async (req, res) => {
if (!farmFetcherV3.isChainSupported(chainId)) {
return res.status(400).json({ error: 'Chain not supported' })
}
const farms = farmsV3ConfigChainMap[chainId]
const farms = legacyFarmsV3ConfigChainMap[chainId]

const commonPrice = await fetchCommonTokenUSDValue(priceHelperTokens[chainId])

Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/pages/v2/pair/[[...currency]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { styled } from 'styled-components'
import { CHAIN_IDS } from 'utils/wagmi'
import Page from 'views/Page'

import { getFarmConfig } from '@pancakeswap/farms/constants'
import { getLegacyFarmConfig } from '@pancakeswap/farms'
import { useTranslation } from '@pancakeswap/localization'
import { useQuery } from '@tanstack/react-query'
import { LightGreyCard } from 'components/Card'
Expand Down Expand Up @@ -66,7 +66,7 @@ export default function PoolV2Page() {
queryKey: ['isFarmExistActiveForPair', chainId, pair?.liquidityToken?.address],

queryFn: async () => {
const farmsConfig = (await getFarmConfig(chainId)) || []
const farmsConfig = (await getLegacyFarmConfig(chainId)) || []
const farmPair = farmsConfig.find(
(farm) => farm.lpAddress.toLowerCase() === pair?.liquidityToken?.address?.toLowerCase(),
)
Expand Down
30 changes: 17 additions & 13 deletions apps/web/src/state/farms/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
import { DeserializedFarmsState, DeserializedFarmUserData, supportedChainIdV2 } from '@pancakeswap/farms'
import { getFarmConfig } from '@pancakeswap/farms/constants'
import { fetchV3FarmsAvgInfo } from 'queries/farms'
import {
DeserializedFarmsState,
DeserializedFarmUserData,
getLegacyFarmConfig,
supportedChainIdV2,
} from '@pancakeswap/farms'
import { useQuery } from '@tanstack/react-query'
import { SLOW_INTERVAL } from 'config/constants'
import { useActiveChainId } from 'hooks/useActiveChainId'
import { useBCakeProxyContractAddress } from 'hooks/useBCakeProxyContractAddress'
import { fetchV3FarmsAvgInfo } from 'queries/farms'
import { useMemo } from 'react'
import { useSelector } from 'react-redux'
import { useAppDispatch } from 'state'
import { getMasterChefContract } from 'utils/contractHelpers'
import { useBCakeProxyContractAddress } from 'hooks/useBCakeProxyContractAddress'

import useAccountActiveChain from 'hooks/useAccountActiveChain'
import { V2FarmWithoutStakedValue, V3FarmWithoutStakedValue } from 'state/farms/types'
import {
farmSelector,
makeFarmFromPidSelector,
makeLpTokenPriceFromLpSymbolSelector,
makeUserFarmFromPidSelector,
} from './selectors'
import {
fetchBCakeWrapperDataAsync,
fetchBCakeWrapperUserDataAsync,
fetchFarmsPublicDataAsync,
fetchFarmUserDataAsync,
} from '.'
import {
farmSelector,
makeFarmFromPidSelector,
makeLpTokenPriceFromLpSymbolSelector,
makeUserFarmFromPidSelector,
} from './selectors'

export function useFarmsLength() {
const { chainId } = useActiveChainId()
Expand All @@ -33,7 +37,7 @@ export function useFarmsLength() {
queryFn: async () => {
const mc = getMasterChefContract(undefined, chainId)
if (!mc) {
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)
const maxPid = farmsConfig?.length ? Math.max(...farmsConfig?.map((farm) => farm.pid)) : undefined
return maxPid ? maxPid + 1 : 0
}
Expand Down Expand Up @@ -125,7 +129,7 @@ export const usePollFarmsWithUserData = () => {
if (!chainId) {
throw new Error('ChainId is not defined')
}
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)

if (!farmsConfig) {
throw new Error('Failed to fetch farm config')
Expand All @@ -152,7 +156,7 @@ export const usePollFarmsWithUserData = () => {
queryKey: name,

queryFn: async () => {
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)

if (!chainId || !farmsConfig || !account) return
const pids = farmsConfig.map((farmToFetch) => farmToFetch.pid)
Expand Down
17 changes: 8 additions & 9 deletions apps/web/src/state/farms/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import { ChainId } from '@pancakeswap/chains'
import { createFarmFetcher, SerializedFarm, SerializedFarmsState } from '@pancakeswap/farms'
import { getFarmConfig } from '@pancakeswap/farms/constants'
import { createFarmFetcher, getLegacyFarmConfig, SerializedFarm, SerializedFarmsState } from '@pancakeswap/farms'
import { createAsyncThunk, createSlice, isAnyOf } from '@reduxjs/toolkit'
import type {
UnknownAsyncThunkFulfilledAction,
UnknownAsyncThunkPendingAction,
UnknownAsyncThunkRejectedAction,
} from '@reduxjs/toolkit/dist/matchers'
import BigNumber from 'bignumber.js'
import { getFarmsPriceHelperLpFiles } from 'config/constants/priceHelperLps'
import stringify from 'fast-json-stable-stringify'
import keyBy from 'lodash/keyBy'
import { fetchStableFarmsAvgInfo, fetchV2FarmsAvgInfo } from 'queries/farms'
import type { AppState } from 'state'
import { chainIdToExplorerInfoChainName, explorerApiClient } from 'state/info/api/client'
import { verifyBscNetwork } from 'utils/verifyBscNetwork'
import { getViemClients } from 'utils/viem'
import { chains } from 'utils/wagmi'
import { Address } from 'viem'
import splitProxyFarms from 'views/Farms/components/YieldBooster/helpers/splitProxyFarms'
import BigNumber from 'bignumber.js'
import { chainIdToExplorerInfoChainName, explorerApiClient } from 'state/info/api/client'
import { resetUserState } from '../global/actions'
import {
fetchFarmBCakeWrapperUserAllowances,
Expand All @@ -38,7 +37,7 @@ const fetchFarmPublicDataPkg = async ({
chainId,
chain,
}): Promise<[SerializedFarm[], number, number, string, Record<string, number>]> => {
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)
const farmsCanFetch = farmsConfig?.filter((farmConfig) => pids.includes(farmConfig.pid)) ?? []
const priceHelperLpsConfig = getFarmsPriceHelperLpFiles(chainId)

Expand Down Expand Up @@ -118,7 +117,7 @@ export const fetchInitialFarmsData = createAsyncThunk<
state: AppState
}
>('farms/fetchInitialFarmsData', async ({ chainId }) => {
return getFarmConfig(chainId).then((farmDataList) => {
return getLegacyFarmConfig(chainId).then((farmDataList) => {
return {
data:
farmDataList?.map((farm) => ({
Expand Down Expand Up @@ -322,7 +321,7 @@ export const fetchFarmUserDataAsync = createAsyncThunk<
await dispatch(fetchInitialFarmsData({ chainId }))
}
const poolLength = state.farms.poolLength ?? (await fetchMasterChefFarmPoolLength(ChainId.BSC))
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)
const farmsCanFetch =
farmsConfig?.filter((farmConfig) => pids.includes(farmConfig.pid) && poolLength > farmConfig.pid) ?? []
if (proxyAddress && farmsCanFetch?.length && verifyBscNetwork(chainId)) {
Expand Down Expand Up @@ -365,7 +364,7 @@ export const fetchBCakeWrapperUserDataAsync = createAsyncThunk<
if (state.farms.chainId !== chainId) {
await dispatch(fetchInitialFarmsData({ chainId }))
}
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)
const farmsCanFetch = farmsConfig?.filter((farmConfig) => pids.includes(farmConfig.pid)) ?? []
if (farmsCanFetch?.length) {
const normalAllowances = await getBCakeWrapperFarmsStakeValue(farmsCanFetch, account, chainId)
Expand Down Expand Up @@ -399,7 +398,7 @@ export const fetchBCakeWrapperDataAsync = createAsyncThunk<
if (state.farms.chainId !== chainId) {
await dispatch(fetchInitialFarmsData({ chainId }))
}
const farmsConfig = await getFarmConfig(chainId)
const farmsConfig = await getLegacyFarmConfig(chainId)
const farmsCanFetch = farmsConfig?.filter((farmConfig) => pids.includes(farmConfig.pid)) ?? []
if (farmsCanFetch?.length) {
const normalAllowances = await getBCakeWrapperFarmsData(farmsCanFetch, chainId)
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/state/farmsV3/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
supportedChainIdV3,
} from '@pancakeswap/farms'
import { priceHelperTokens } from '@pancakeswap/farms/constants/common'
import { farmsV3ConfigChainMap } from '@pancakeswap/farms/constants/v3'
import { legacyFarmsV3ConfigChainMap } from '@pancakeswap/farms/constants/v3'
import { bCakeFarmBoosterVeCakeABI } from '@pancakeswap/farms/constants/v3/abi/bCakeFarmBoosterVeCake'
import { TvlMap, fetchCommonTokenUSDValue } from '@pancakeswap/farms/src/fetchFarmsV3'
import { deserializeToken } from '@pancakeswap/token-lists'
Expand Down Expand Up @@ -83,7 +83,7 @@ export const useFarmsV3Public = () => {
}

// direct copy from api routes, the client side fetch is preventing cache due to migration phase we want fresh data
const farms = farmsV3ConfigChainMap[chainId as ChainId]
const farms = legacyFarmsV3ConfigChainMap[chainId as ChainId]

const commonPrice = await fetchCommonTokenUSDValue(priceHelperTokens[chainId ?? -1])

Expand Down
50 changes: 6 additions & 44 deletions apps/web/src/state/farmsV4/state/accountPositions/fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { ChainId } from '@pancakeswap/chains'
import { BCakeWrapperFarmConfig, Protocol, UNIVERSAL_BCAKEWRAPPER_FARMS, UNIVERSAL_FARMS } from '@pancakeswap/farms'
import { BCakeWrapperFarmConfig, Protocol, UNIVERSAL_FARMS, UNIVERSAL_FARMS_MAP } from '@pancakeswap/farms'
import { CurrencyAmount, ERC20Token, Pair, Token, pancakePairV2ABI } from '@pancakeswap/sdk'
import { LegacyStableSwapPair } from '@pancakeswap/smart-router/legacy-router'
import { deserializeToken } from '@pancakeswap/token-lists'
import BigNumber from 'bignumber.js'
import { infoStableSwapABI } from 'config/abi/infoStableSwap'
import { masterChefV2ABI } from 'config/abi/masterchefV2'
import { v2BCakeWrapperABI } from 'config/abi/v2BCakeWrapper'
import { BASES_TO_TRACK_LIQUIDITY_FOR, PINNED_PAIRS } from 'config/constants/exchange'
import memoize from 'lodash/memoize'
import uniqWith from 'lodash/uniqWith'
import { AppState } from 'state'
import { safeGetAddress } from 'utils'
import { getCrossFarmingVaultAddress, getMasterChefV2Address } from 'utils/addressHelpers'
import { publicClient } from 'utils/viem'
import { Address, erc20Abi, isAddressEqual, zeroAddress } from 'viem'
import { Address, erc20Abi, zeroAddress } from 'viem'
import { StablePoolInfo, V2PoolInfo } from '../type'
import { StableLPDetail, V2LPDetail } from './type'

Expand All @@ -33,41 +30,6 @@ export function getV2LiquidityToken([tokenA, tokenB]: [ERC20Token, ERC20Token]):
)
}

export const getAccountV2FarmingStakedBalances = async (
chainId: number,
account: Address,
pools: Array<V2PoolInfo | StablePoolInfo>,
) => {
const masterChefV2Address =
chainId === ChainId.BSC ? getMasterChefV2Address(chainId) : getCrossFarmingVaultAddress(chainId)
if (!account || !chainId || pools.length === 0 || !masterChefV2Address) return []

const validPools = pools.filter(
(pool) => ['v2', 'stable'].includes(pool.protocol) && pool.pid && pool.chainId === chainId,
)
const client = publicClient({ chainId })

const balanceCalls = validPools.map((pool) => {
return {
abi: masterChefV2ABI,
address: masterChefV2Address,
functionName: 'userInfo',
args: [BigInt(pool.pid!), account] as const,
} as const
})

const balances = await client
.multicall({
contracts: balanceCalls,
allowFailure: true,
})
.then((res) => res.map((item) => item.result ?? [0n, 0n, 0n]))

return balances.map((balance) => {
return new BigNumber(balance[0].toString()).toString()
})
}

export const getAccountV2FarmingBCakeWrapperEarning = async (
chainId: number,
account: Address,
Expand Down Expand Up @@ -111,7 +73,9 @@ export const getTrackedV2LpTokens = memoize(
): [ERC20Token, ERC20Token][] => {
const pairTokens: ITokenPair[] = []
// from farms
UNIVERSAL_FARMS.filter((farm) => farm.protocol === 'v2' && farm.pid && farm.chainId === chainId).forEach((farm) => {
UNIVERSAL_FARMS.filter(
(farm) => farm.protocol === 'v2' && farm.bCakeWrapperAddress && farm.chainId === chainId,
).forEach((farm) => {
pairTokens.push(farm.token0.sortsBefore(farm.token1) ? [farm.token0, farm.token1] : [farm.token1, farm.token0])
})
// from pinned pairs
Expand Down Expand Up @@ -153,9 +117,7 @@ const V2_UNIVERSAL_FARMS = UNIVERSAL_FARMS.filter((farm) => farm.protocol === Pr
const STABLE_UNIVERSAL_FARMS = UNIVERSAL_FARMS.filter((farm) => farm.protocol === Protocol.STABLE)

export const getBCakeWrapperAddress = (lpAddress: Address, chainId: number) => {
const f = UNIVERSAL_BCAKEWRAPPER_FARMS.find((farm) => {
return isAddressEqual(farm.lpAddress, lpAddress) && farm.chainId === chainId
})
const f = UNIVERSAL_FARMS_MAP[`${chainId}:${lpAddress}`] as V2PoolInfo | StablePoolInfo | undefined

return f?.bCakeWrapperAddress ?? '0x'
}
Expand Down
25 changes: 20 additions & 5 deletions apps/web/src/state/farmsV4/state/extendPools/fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getChainNameInKebabCase } from '@pancakeswap/chains'
import { UNIVERSAL_FARMS } from '@pancakeswap/farms'
import { UNIVERSAL_FARMS, UNIVERSAL_FARMS_MAP } from '@pancakeswap/farms'
import set from 'lodash/set'
import { chainIdToExplorerInfoChainName, explorerApiClient } from 'state/info/api/client'
import { PoolInfo } from '../type'
import { PoolInfo, StablePoolInfo, V2PoolInfo } from '../type'
import { parseFarmPools } from '../utils'
import { ExtendPoolsQuery } from './atom'

Expand Down Expand Up @@ -42,11 +43,25 @@ export const fetchExplorerPoolsList = async (query: Required<ExtendPoolsQuery>,
}
}

export const fetchExplorerPoolInfo = async (
const composeFarmConfig = (farm: PoolInfo) => {
if (farm.protocol !== 'stable' && farm.protocol !== 'v2') return farm

const localFarm = UNIVERSAL_FARMS_MAP[`${farm.chainId}:${farm.lpAddress}`] as V2PoolInfo | StablePoolInfo | undefined

if (!localFarm) {
return farm
}

set(farm, 'bCakeWrapperAddress', localFarm.bCakeWrapperAddress)

return farm
}

export const fetchExplorerPoolInfo = async <TPoolType extends PoolInfo>(
poolAddress: string,
chainId: number,
signal?: AbortSignal,
): Promise<PoolInfo | null> => {
): Promise<TPoolType | null> => {
const chainName = chainIdToExplorerInfoChainName[chainId]
const resp = await explorerApiClient.GET('/cached/pools/{chainName}/{id}', {
signal,
Expand All @@ -65,5 +80,5 @@ export const fetchExplorerPoolInfo = async (
resp.data.chainId = chainId
const isFarming = UNIVERSAL_FARMS.some((farm) => farm.lpAddress === poolAddress)

return parseFarmPools([resp.data], { isFarming })[0]
return composeFarmConfig(parseFarmPools([resp.data], { isFarming })[0]) as TPoolType
}
6 changes: 3 additions & 3 deletions apps/web/src/state/farmsV4/state/extendPools/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,18 @@ export const getPoolAddressByToken = memoize(
`${chainId}#${token0Address}#${token1Address}#${fee}`,
)

export const usePoolInfo = ({
export const usePoolInfo = <TPoolType extends PoolInfo>({
poolAddress,
chainId,
}: {
poolAddress: string | null
chainId: number
}): PoolInfo | undefined | null => {
}): TPoolType | undefined | null => {
const { data: poolInfo } = useQuery({
queryKey: ['poolInfo', chainId, poolAddress],
queryFn: () => fetchExplorerPoolInfo(poolAddress ?? '', chainId),
enabled: !!poolAddress && !!chainId,
})

return poolInfo
return poolInfo as TPoolType | undefined | null
}
Loading

0 comments on commit a6be81d

Please sign in to comment.