Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Merkl tag on farms #11103

Merged
merged 12 commits into from
Jan 3, 2025
1 change: 0 additions & 1 deletion apps/web/src/components/Merkl/MerklSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export function MerklSection({
}: {
poolAddress?: `0x${string}`
chainId?: ChainId
tokenId?: bigint
notEnoughLiquidity: boolean
outRange: boolean
disabled: boolean
Expand Down
32 changes: 16 additions & 16 deletions apps/web/src/config/constants/merklPools.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
[
{
"chainId": 56,
"address": "0xd5a79aB649E0a5F20e995026d034a0bF28B8aACa",
"link": "https://merkl.angle.money/bnb%20smart%20chain/pool/2/0xd5a79aB649E0a5F20e995026d034a0bF28B8aACa"
},
{
"chainId": 56,
"address": "0xeD000AB362Ef11E962658Fc04c1A7D667a647213",
"link": "https://merkl.angle.money/bnb%20smart%20chain/pool/1/0xeD000AB362Ef11E962658Fc04c1A7D667a647213"
},
{
"chainId": 42161,
"address": "0xE4BfcC208f3447cc5D2f5CCB40C52778d4bE2004",
"link": "https://merkl.angle.money/arbitrum/pool/2/0xE4BfcC208f3447cc5D2f5CCB40C52778d4bE2004"
"chainId": 1,
"address": "0x6db0f81Db2C3B2A85a802d511577d8522D0D8C14",
"link": "https://merkl.angle.money/ethereum/pool/2/0x6db0f81Db2C3B2A85a802d511577d8522D0D8C14"
},
{
"chainId": 1,
Expand All @@ -25,8 +15,18 @@
"link": "https://merkl.angle.money/bnb%20smart%20chain/pool/2/0x9d84f1d12FdC6c977BF451e70689F45107b79b77"
},
{
"chainId": 1,
"address": "0x6db0f81Db2C3B2A85a802d511577d8522D0D8C14",
"link": "https://merkl.angle.money/ethereum/pool/2/0x6db0f81Db2C3B2A85a802d511577d8522D0D8C14"
"chainId": 56,
"address": "0xeD000AB362Ef11E962658Fc04c1A7D667a647213",
"link": "https://merkl.angle.money/bnb%20smart%20chain/pool/1/0xeD000AB362Ef11E962658Fc04c1A7D667a647213"
},
{
"chainId": 56,
"address": "0xd5a79aB649E0a5F20e995026d034a0bF28B8aACa",
"link": "https://merkl.angle.money/bnb%20smart%20chain/pool/2/0xd5a79aB649E0a5F20e995026d034a0bF28B8aACa"
},
{
"chainId": 42161,
"address": "0xE4BfcC208f3447cc5D2f5CCB40C52778d4bE2004",
"link": "https://merkl.angle.money/arbitrum/pool/2/0xE4BfcC208f3447cc5D2f5CCB40C52778d4bE2004"
}
]
84 changes: 44 additions & 40 deletions apps/web/src/hooks/useMerkl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useWalletClient } from 'wagmi'
import { useMasterchefV3 } from 'hooks/useContract'
import { isAddressEqual } from 'utils'
import { useCurrentBlockTimestamp as useBlockTimestamp } from 'state/block/hooks'
import { supportedChainIdV4 } from '@pancakeswap/farms'

export const MERKL_API_V4 = 'https://api.merkl.xyz/v4'

Expand All @@ -41,12 +42,12 @@ export function useMerklInfo(poolAddress?: string): {
const lists = useAllLists()

const { data, isPending, refetch } = useQuery({
queryKey: [`fetchMerkl-${chainId}`],
queryKey: [`fetchMerklPools`],
queryFn: async () => {
if (!chainId) return undefined

const responsev4 = await fetch(
`${MERKL_API_V4}/opportunities?chainId=${chainId}&test=false&items=1000&action=POOL,HOLD`,
`${MERKL_API_V4}/opportunities?${supportedChainIdV4.join(
',',
)}&test=false&items=1000&action=POOL,HOLD&status=LIVE`,
)

if (!responsev4.ok) {
Expand All @@ -57,7 +58,7 @@ export function useMerklInfo(poolAddress?: string): {

const opportunities = merklDataV4?.filter(
(opportunity) =>
opportunity?.tokens?.[0]?.symbol?.toLowerCase().startsWith('Cake-LP') ||
opportunity?.tokens?.[0]?.symbol?.toLowerCase().startsWith('cake-lp') ||
opportunity?.protocol?.id?.toLowerCase().startsWith('pancakeswap'),
)

Expand All @@ -76,7 +77,7 @@ export function useMerklInfo(poolAddress?: string): {

return { pools }
},
enabled: Boolean(chainId && poolAddress),
enabled: Boolean(poolAddress),
staleTime: FAST_INTERVAL,
retryDelay: (attemptIndex) => Math.min(2000 * 2 ** attemptIndex, 30000),
})
Expand All @@ -96,15 +97,17 @@ export function useMerklInfo(poolAddress?: string): {

if (!merklDataV4) return undefined

return merklDataV4?.[0] || {}
return merklDataV4
},
enabled: Boolean(data && chainId && account && poolAddress),
staleTime: FAST_INTERVAL,
retryDelay: (attemptIndex) => Math.min(2000 * 2 ** attemptIndex, 30000),
})

return useMemo(() => {
if (!data || !currentTimestamp)
const pool = data?.pools?.filter((opportunity) => isAddressEqual(opportunity.identifier, poolAddress))?.[0]

if (!pool || !currentTimestamp)
return {
rewardsPerToken: [],
rewardTokenAddresses: [],
Expand All @@ -114,14 +117,10 @@ export function useMerklInfo(poolAddress?: string): {
isPending,
}

const { pools } = data

const hasLive = pools.some((pool) => {
const hasMeanAPR = pool.status === 'LIVE' && pool.apr > 0

if (!hasMeanAPR) return false

const hasLiveDistribution = Boolean(
const hasLive =
pool.status === 'LIVE' &&
pool.apr > 0 &&
Boolean(
pool.campaigns?.some((campaign) => {
const { startTimestamp, endTimestamp, whitelist, blacklist } = campaign
const startTimestampNumber = Number(startTimestamp)
Expand All @@ -144,14 +143,19 @@ export function useMerklInfo(poolAddress?: string): {
}),
)

return hasLiveDistribution
})
const rewardAddresses = (
pool.rewardsRecord?.breakdowns?.flatMap((breakdown) => breakdown.token.address) || []
).filter((address, index, allAddresses) => allAddresses.indexOf(address) === index)

const rewardsPerTokenObject = userData?.rewards?.filter((reward) => {
const { amount, claimed } = reward || {}
const unclaimed = BigInt(amount || 0) - BigInt(claimed || 0)
return unclaimed > 0
})
const chainUserData = userData?.filter((chainUserReward) => chainUserReward?.chain?.id === pool.chainId)?.[0]

const rewardsPerTokenObject = chainUserData?.rewards
?.filter((reward) => rewardAddresses.some((rewardAddress) => isAddressEqual(reward.token.address, rewardAddress)))
.filter((reward) => {
const { amount, claimed } = reward || {}
const unclaimed = BigInt(amount || 0) - BigInt(claimed || 0)
return unclaimed > 0
})

const transactionData = rewardsPerTokenObject?.reduce((acc, reward) => {
// eslint-disable-next-line no-param-reassign
Expand Down Expand Up @@ -183,31 +187,31 @@ export function useMerklInfo(poolAddress?: string): {

const { rewardsPerToken = [], rewardTokenAddresses = [], ...rest } = rewardResult

const rewardCurrencies = (rewardTokenAddresses as string[])
.reduce<TokenInfo[]>((result, address) => {
Object.values(lists).find((list) => {
const token: TokenInfo | undefined = list?.current?.tokens.find((t) => isAddressEqual(t.address, address))
const rewardCurrencies = rewardsPerToken.length
? rewardsPerToken
: (rewardTokenAddresses as string[])
.reduce<TokenInfo[]>((result, address) => {
Object.values(lists).find((list) => {
const token: TokenInfo | undefined = list?.current?.tokens.find((t) => isAddressEqual(t.address, address))

if (token) return result.push(token)
if (token) return result.push(token)

return false
})
return false
})

return result
}, [])
.map((info) => {
const t = new Token(chainId as number, info.address, info.decimals, info.symbol)
return result
}, [])
.map((info) => {
const t = new Token(chainId as number, info.address, info.decimals, info.symbol)

return CurrencyAmount.fromRawAmount(t, '0')
})
return CurrencyAmount.fromRawAmount(t, '0')
})

const merklApr = data?.pools?.find((pool) => isAddressEqual(pool.identifier, poolAddress))?.apr as
| number
| undefined
const merklApr = pool?.apr as number | undefined

return {
...rest,
rewardsPerToken: rewardsPerToken.length ? rewardsPerToken : rewardCurrencies,
rewardsPerToken: rewardCurrencies,
refreshData: refetch,
merklApr,
}
Expand Down
6 changes: 4 additions & 2 deletions apps/web/src/pages/v2/pair/[[...currency]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ import { useRouter } from 'next/router'
import { useAccount } from 'wagmi'
import { useAccountPositionDetailByPool } from 'state/farmsV4/state/accountPositions/hooks'
import { usePoolInfo } from 'state/farmsV4/state/extendPools/hooks'
import { useMemo } from 'react'
import React, { useMemo } from 'react'
import { formatFiatNumber } from '@pancakeswap/utils/formatFiatNumber'
import { useTotalPriceUSD } from 'hooks/useTotalPriceUSD'
import { useLPApr } from 'state/swap/useLPApr'
import { formatAmount } from 'utils/formatInfoNumbers'
import { MerklSection } from 'components/Merkl/MerklSection'
import { MerklTag } from 'components/Merkl/MerklTag'

export const BodyWrapper = styled(Card)`
border-radius: 24px;
Expand Down Expand Up @@ -147,6 +148,7 @@ export default function PoolV2Page() {
<Heading as="h2" ml="8px">
{pair?.token0?.symbol}-{pair?.token1?.symbol} LP
</Heading>
<MerklTag poolAddress={pair?.liquidityToken?.address} />
</Flex>
}
backTo="/liquidity/positions"
Expand Down Expand Up @@ -273,7 +275,7 @@ export default function PoolV2Page() {
{t('LP reward APR')}: {formatAmount(poolData.lpApr)}%
</Text>
)}
<Text color="textSubtle" ml="4px">
<Text color="textSubtle">
{t('Your share in pool')}: {poolTokenPercentage ? `${poolTokenPercentage.toFixed(8)}%` : '-'}
</Text>
</Flex>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/state/farmsV4/state/poolApr/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export const getAllNetworkMerklApr = async (signal?: AbortSignal) => {
const result = await resp.json()
const pancakeResult = result?.filter(
(opportunity) =>
opportunity?.tokens?.[0].name?.toLowerCase().startsWith('pancake') ||
opportunity?.tokens?.[0]?.symbol?.toLowerCase().startsWith('cake-lp') ||
opportunity?.protocol?.id?.toLowerCase().startsWith('pancakeswap'),
)
const aprs = await Promise.all(supportedChainIdV4.map((chainId) => getMerklApr(pancakeResult, chainId)))
Expand Down
3 changes: 3 additions & 0 deletions apps/web/src/views/Farms/hooks/useLmPoolLiquidity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const fetchLmPoolLiquidity = async (lpAddress: Address, chainId: number): Promis
abi: pancakeV3PoolABI,
functionName: 'lmPool',
})

if (isAddressEqual(lmPool, zeroAddress)) return 0n

const lmPoolLiquidity = await client.readContract({
address: lmPool,
abi: lmPoolAbi,
Expand Down
8 changes: 7 additions & 1 deletion scripts/updateMerkl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@ const fetchAllMerklConfig = async (): Promise<any[]> => {

const parseMerklConfig = (merklConfigResponse: any[]): MerklConfigPool[] => {
return merklConfigResponse
.sort((a, b) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to avoid updates without any changes

if (a.chainId === b.chainId) {
return a.id - b.id
}
return a.chainId - b.chainId
})
.filter(
(opportunity) =>
(opportunity?.tokens?.[0].name?.toLowerCase().startsWith('pancake') ||
(opportunity?.tokens?.[0]?.symbol?.toLowerCase().startsWith('cake-lp') ||
opportunity?.protocol?.id?.toLowerCase().startsWith('pancakeswap')) &&
opportunity?.apr > 0,
)
Expand Down
Loading