Skip to content

Commit

Permalink
feat: farm-config-v2 (#10571)
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 focuses on adding support for stable swap addresses in farms
configuration and updating related functions and configurations.

### Detailed summary
- Added `stableSwapAddress` field to `UniversalFarmConfigStableSwap`
- Updated functions to use `stableSwapAddress` instead of
`stableLpAddress`
- Added support for fetching stable swap pairs in functions
- Modified configuration files to include `stableSwapAddress` field

> The following files were skipped due to too many changes:
`packages/farms/src/utils.ts`

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

<!-- end pr-codex -->
  • Loading branch information
ChefJerry authored Aug 29, 2024
1 parent b0d3ac4 commit 5b98344
Show file tree
Hide file tree
Showing 15 changed files with 195 additions and 15 deletions.
42 changes: 42 additions & 0 deletions apps/web/src/pages/api/configs/farms/v2/[chain].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ChainId, chainNames, chainNameToChainId } from '@pancakeswap/chains'
import { formatUniversalFarmToSerializedFarm, UNIVERSAL_FARMS } from '@pancakeswap/farms'
import { NextApiHandler } from 'next'
import { stringify } from 'viem'
import { enum as enum_, nativeEnum } from 'zod'

const allChainNames = Object.values(chainNames) as [string, ...string[]]

const zChain = nativeEnum(ChainId).or(enum_(allChainNames))

const handler: NextApiHandler = async (req, res) => {
const isChainInt = !Number.isNaN(parseInt(req.query.chain as string, 10))
const chainQuery = isChainInt ? Number(req.query.chain) : req.query.chain
const parsedChain = zChain.safeParse(chainQuery)

if (!parsedChain.success) {
return res.status(400).json({ error: parsedChain.error })
}

const chainId = isChainInt ? Number(parsedChain.data) : Number(chainNameToChainId[parsedChain.data])

if (!chainId) {
return res.status(400).json({ error: 'Invalid chain' })
}

try {
const farmConfig = UNIVERSAL_FARMS.filter((farm) => farm.chainId === chainId)
const legacyFarmConfig = formatUniversalFarmToSerializedFarm(farmConfig)
// cache for long time, it should revalidate on every deployment
res.setHeader('Cache-Control', `max-age=10800, s-maxage=31536000`)

return res.status(200).json({
data: JSON.parse(stringify(legacyFarmConfig)),
lastUpdatedAt: new Date().toISOString,
})
} catch (error) {
console.error(error)
return res.status(500).json({ error: JSON.parse(stringify(error)) })
}
}

export default handler
24 changes: 24 additions & 0 deletions apps/web/src/pages/api/configs/farms/v2/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { formatUniversalFarmToSerializedFarm, UNIVERSAL_FARMS, UNIVERSAL_FARMS_WITH_TESTNET } from '@pancakeswap/farms'
import { NextApiHandler } from 'next'
import { stringify } from 'viem'

const handler: NextApiHandler = async (req, res) => {
const includeTestnet = !!req.query.includeTestnet

try {
const farmConfig = includeTestnet ? UNIVERSAL_FARMS : UNIVERSAL_FARMS_WITH_TESTNET
const legacyFarmConfig = formatUniversalFarmToSerializedFarm(farmConfig)
// cache for long time, it should revalidate on every deployment
res.setHeader('Cache-Control', `max-age=10800, s-maxage=31536000`)

return res.status(200).json({
data: JSON.parse(stringify(legacyFarmConfig)),
lastUpdatedAt: new Date().toISOString,
})
} catch (error) {
console.error(error)
return res.status(500).json({ error: JSON.parse(stringify(error)) })
}
}

export default handler
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const useAccountPositionDetailByPool = <TProtocol extends keyof PoolPosit
}
if (protocol === 'stable') {
const stablePair = LegacyRouter.stableSwapPairsByChainId[chainId].find((pair) => {
return isAddressEqual(pair.stableSwapAddress, poolInfo?.stableLpAddress as Address)
return isAddressEqual(pair.stableSwapAddress, poolInfo?.stableSwapAddress as Address)
})
return getStablePairDetails(chainId, account!, stablePair ? [stablePair] : [])
}
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/state/farmsV4/state/poolApr/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,15 +432,15 @@ const getV2PoolsCakeAprByChainId = async (
address: pool.token0.wrapped.address,
functionName: 'balanceOf',
abi: erc20Abi,
args: [pool.stableLpAddress ?? pool.lpAddress],
args: [pool.stableSwapAddress ?? pool.lpAddress],
} as const
})
const reserve1Calls = validPools.map((pool) => {
return {
address: pool.token1.wrapped.address,
functionName: 'balanceOf',
abi: erc20Abi,
args: [pool.stableLpAddress ?? pool.lpAddress],
args: [pool.stableSwapAddress ?? pool.lpAddress],
} as const
})

Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/state/farmsV4/state/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type BasePoolInfo = {
pid?: number
chainId: number
lpAddress: Address
stableLpAddress?: Address
stableSwapAddress?: Address
protocol: Protocol
token0: Currency
token1: Token
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/state/farmsV4/state/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const parseFarmPools = (
chainId: pool.chainId,
pid,
lpAddress,
stableLpAddress: stableSwapAddress,
stableSwapAddress,
protocol: pool.protocol as Protocol,
token0,
token1,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/views/PoolDetail/components/PoolStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const PoolStatus: React.FC<PoolStatusProps> = ({ poolInfo }) => {
}

const stablePair = LegacyRouter.stableSwapPairsByChainId[poolInfo.chainId].find((pair) => {
return isAddressEqual(pair.stableSwapAddress, poolInfo?.stableLpAddress as Address)
return isAddressEqual(pair.stableSwapAddress, poolInfo?.stableSwapAddress as Address)
})

if (!stablePair) return 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ export const PoolListItemAction = memo(({ pool }: { pool: PoolInfo }) => {
export const getPoolDetailPageLink = (pool: PoolInfo) => {
const linkPrefix = `/liquidity/pool${multiChainPaths[pool.chainId] || '/bsc'}`
if (pool.protocol === Protocol.STABLE) {
if (pool.stableLpAddress) {
return `${linkPrefix}/${pool.stableLpAddress}`
if (pool.stableSwapAddress) {
return `${linkPrefix}/${pool.stableSwapAddress}`
}
const ssPair = LegacyRouter.stableSwapPairsByChainId[pool.chainId]?.find((pair) => {
return isAddressEqual(pair.lpAddress, pool.lpAddress)
Expand Down
1 change: 1 addition & 0 deletions packages/farms/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ test('exports', () => {
"isStableFarm",
"Protocol",
"isActiveV3Farm",
"formatUniversalFarmToSerializedFarm",
"deserializeFarm",
"deserializeFarmUserData",
"deserializeFarmBCakeUserData",
Expand Down
1 change: 1 addition & 0 deletions packages/farms/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@pancakeswap/price-api-sdk": "workspace:*",
"@pancakeswap/chains": "workspace:*",
"@pancakeswap/sdk": "workspace:*",
"@pancakeswap/stable-swap-sdk": "workspace:*",
"@pancakeswap/swap-sdk-core": "workspace:*",
"@pancakeswap/token-lists": "workspace:*",
"@pancakeswap/tokens": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions packages/farms/src/farms/arb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,7 @@ export const arbFarmConfig: UniversalFarmConfig[] = [
token0: arbitrumTokens.dlp,
token1: arbitrumTokens.mdlp,
lpAddress: '0x0db5e247ab73FBaE16d9301f2977f974EC0AA336',
stableSwapAddress: '0xd0f0be815a76eFE677c92b07b39a5e972BAf22bD',
},
{
pid: 178,
Expand All @@ -833,6 +834,7 @@ export const arbFarmConfig: UniversalFarmConfig[] = [
token0: arbitrumTokens.pendle,
token1: arbitrumTokens.mpendle,
lpAddress: '0x1A2329546f11e4fE55b853D98Bba2c4678E3105A',
stableSwapAddress: '0x73ed25e04Aa673ddf7411441098fC5ae19976CE0',
},
]

Expand Down
12 changes: 9 additions & 3 deletions packages/farms/src/farms/bsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,7 @@ export const bscFarmConfig: UniversalFarmConfig[] = [
chainId: ChainId.BSC,
protocol: Protocol.STABLE,
lpAddress: '0x4cBEa76B4A1c42C356B4c52B0314A98313fFE9df',
stableSwapAddress: '0xfF5Ce4846A3708EA9befa6c3Ab145e63f65DC045',
token0: bscTokens.mwbeth,
token1: bscTokens.wbeth,
},
Expand All @@ -1713,6 +1714,7 @@ export const bscFarmConfig: UniversalFarmConfig[] = [
token0: bscTokens.mdlp,
token1: bscTokens.dlp,
lpAddress: '0xA2915ae3bc8C6C03f59496B6Dd26aa6a4335b788',
stableSwapAddress: '0x25d0eD3b1cE5aF0F3Ac7da4b39B46FC409bF67e2',
},
{
pid: 178,
Expand All @@ -1721,6 +1723,7 @@ export const bscFarmConfig: UniversalFarmConfig[] = [
token0: bscTokens.mpendle,
token1: bscTokens.pendle,
lpAddress: '0x183F325b33d190597D80d1B46D865d0250fD9BF2',
stableSwapAddress: '0xD8CB82059da7215b1a9604E845d49D3e78d0f95A',
},
{
pid: 177,
Expand Down Expand Up @@ -1750,25 +1753,28 @@ export const bscFarmConfig: UniversalFarmConfig[] = [
pid: 173,
chainId: ChainId.BSC,
protocol: Protocol.STABLE,
lpAddress: '0xB1D54d76E2cB9425Ec9c018538cc531440b55dbB',
token0: bscTokens.cake,
token1: bscTokens.sdcake,
lpAddress: '0xB1D54d76E2cB9425Ec9c018538cc531440b55dbB',
stableSwapAddress: '0xb8204D31379A9B317CD61C833406C972F58ecCbC',
},
{
pid: 174,
chainId: ChainId.BSC,
protocol: Protocol.STABLE,
lpAddress: '0xb9dC6396AcFFD24E0f69Dfd3231fDaeB31514D02',
token0: bscTokens.cake,
token1: bscTokens.mcake,
lpAddress: '0xb9dC6396AcFFD24E0f69Dfd3231fDaeB31514D02',
stableSwapAddress: '0xc54d35a8Cfd9f6dAe50945Df27A91C9911A03ab1',
},
{
pid: 163,
chainId: ChainId.BSC,
protocol: Protocol.STABLE,
lpAddress: '0xB2Aa63f363196caba3154D4187949283F085a488',
token0: bscTokens.hay,
token1: bscTokens.usdt,
lpAddress: '0xB2Aa63f363196caba3154D4187949283F085a488',
stableSwapAddress: '0xb1Da7D2C257c5700612BdE35C8d7187dc80d79f1',
},
{
pid: 42,
Expand Down
11 changes: 8 additions & 3 deletions packages/farms/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,13 @@ export type FarmBaseConfig = {
token1: Token
}

export type UniversalFarmConfigV2AndStableSwap = {
protocol: Protocol.V2 | Protocol.STABLE
export type UniversalFarmConfigStableSwap = {
protocol: Protocol.STABLE
stableSwapAddress: Address
} & FarmBaseConfig

export type UniversalFarmConfigV2 = {
protocol: Protocol.V2
} & FarmBaseConfig

export type UniversalFarmConfigV3 = {
Expand All @@ -344,7 +349,7 @@ export type UniversalFarmConfigV3 = {
/**
* minimal pool info for a farm
*/
export type UniversalFarmConfig = UniversalFarmConfigV2AndStableSwap | UniversalFarmConfigV3
export type UniversalFarmConfig = UniversalFarmConfigV2 | UniversalFarmConfigStableSwap | UniversalFarmConfigV3

// only v2/ss farms have bCakeWrapperAddress
export type BCakeWrapperFarmConfig = {
Expand Down
98 changes: 97 additions & 1 deletion packages/farms/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,101 @@
import { FarmV3Data } from './types'
import { ChainId } from '@pancakeswap/chains'
import { getStableSwapPools } from '@pancakeswap/stable-swap-sdk'
import { isAddressEqual } from 'viem'
import { UNIVERSAL_BCAKEWRAPPER_FARMS } from './farms'
import {
ComputedFarmConfigV3,
FarmV3Data,
SerializedClassicFarmConfig,
SerializedFarmConfig,
SerializedStableFarmConfig,
UniversalFarmConfig,
UniversalFarmConfigStableSwap,
UniversalFarmConfigV2,
UniversalFarmConfigV3,
} from './types'

export function isActiveV3Farm(farm: FarmV3Data, poolLength: number) {
return farm.pid !== 0 && farm.multiplier !== '0X' && poolLength && poolLength >= farm.pid
}

type LegacyFarmConfig = SerializedFarmConfig & { chainId: ChainId; version: 2 | 3 }
type LegacyStableFarmConfig = SerializedStableFarmConfig & { chainId: ChainId; version: 2 | 3 }
type LegacyClassicFarmConfig = SerializedClassicFarmConfig & { chainId: ChainId; version: 2 | 3 }
type LegacyV3FarmConfig = ComputedFarmConfigV3 & { chainId: ChainId; version: 2 | 3 }
export function formatUniversalFarmToSerializedFarm(farms: UniversalFarmConfig[]): Array<LegacyFarmConfig> {
return farms
.map((farm) => {
switch (farm.protocol) {
case 'stable':
return formatStableUniversalFarmToSerializedFarm(farm as UniversalFarmConfigStableSwap)
case 'v2':
return formatV2UniversalFarmToSerializedFarm(farm as UniversalFarmConfigV2)
case 'v3':
return formatV3UniversalFarmToSerializedFarm(farm as UniversalFarmConfigV3)
default:
return undefined
}
})
.filter((farm): farm is LegacyFarmConfig => farm !== undefined)
}

const formatStableUniversalFarmToSerializedFarm = (
farm: UniversalFarmConfigStableSwap,
): LegacyStableFarmConfig | undefined => {
const { chainId, lpAddress, pid, token0, token1, stableSwapAddress } = farm
const stablePair = getStableSwapPools(chainId).find((pair) => {
return isAddressEqual(pair.stableSwapAddress, stableSwapAddress)
})
const bCakeConfig = UNIVERSAL_BCAKEWRAPPER_FARMS.find((config) => {
return chainId === config.chainId && isAddressEqual(config.lpAddress, lpAddress)
})

if (!stablePair) {
console.warn(`Could not find stable pair for farm with stableSwapAddress ${stableSwapAddress}`)
return undefined
}

return {
pid,
lpAddress,
lpSymbol: `${token0.symbol}-${token1.symbol} LP`,
token: token0,
quoteToken: token1,
stableSwapAddress,
stableLpFee: stablePair.stableLpFee,
stableLpFeeRateOfTotalFee: stablePair.stableLpFeeRateOfTotalFee,
infoStableSwapAddress: stablePair.infoStableSwapAddress,
bCakeWrapperAddress: bCakeConfig?.bCakeWrapperAddress,
chainId,
version: 2,
}
}

const formatV2UniversalFarmToSerializedFarm = (farm: UniversalFarmConfigV2): LegacyClassicFarmConfig => {
const { chainId, pid, lpAddress, token0, token1 } = farm
return {
pid,
lpAddress,
lpSymbol: `${token0.symbol}-${token1.symbol} LP`,
token: token0,
quoteToken: token1,
chainId,
version: 2,
}
}

const formatV3UniversalFarmToSerializedFarm = (farm: UniversalFarmConfigV3): LegacyV3FarmConfig => {
const { chainId, pid, lpAddress, token0, token1, feeAmount } = farm
return {
pid,
lpAddress,
lpSymbol: `${token0.symbol}-${token1.symbol} LP`,
token0,
token1,
token: token0,
quoteToken: token1,
feeAmount,
chainId,
version: 3,
}
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5b98344

Please sign in to comment.