Skip to content

Commit

Permalink
feat: cross-chain IFO (#10655)
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 adds support for the Eigenpie IFO on Arbitrum, updates IFO
constants, and refactors hooks and components related to VeCake and
IFOs.

### Detailed summary
- Added Eigenpie IFO on Arbitrum
- Updated IFO constants and ChainNameMap
- Refactored VeCake and IFO-related hooks and components

> The following files were skipped due to too many changes:
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/ClaimButton.tsx`,
`apps/web/src/views/Ifos/hooks/useIfoCredit.ts`,
`packages/ifos/src/queries/fetchUserIfo.ts`,
`apps/web/src/views/Ifos/CurrentIfo.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/index.tsx`,
`apps/web/src/views/Home/components/Banners/hooks/useMultipleBannerConfig.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/IfoCardTokens.tsx`,
`apps/web/src/views/Ifos/components/IfoPoolVaultCard.tsx`,
`packages/widgets-internal/ifo/NoVeCakeCard.tsx`,
`packages/uikit/src/components/Svg/Icons/LinkIcon.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/CrossChainVeCakeTips.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/IfoCardActions.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/StakeVaultButton.tsx`,
`apps/web/src/utils/customGTMEventTracking.ts`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/ActivateProfileButton.tsx`,
`packages/uikit/src/components/Svg/index.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/StakeButton.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/SyncVeCakeButton.tsx`,
`apps/web/src/views/Ifos/hooks/v8/useGetWalletIfoData.ts`,
`apps/web/src/components/CrossChainVeCakeModal/hooks/useProfileProxyWellSynced.ts`,
`packages/widgets-internal/ifo/CrossChainLockInfoCard.tsx`,
`packages/widgets-internal/ifo/CrossChainMyVeCake.tsx`,
`packages/uikit/src/components/Svg/Icons/LinkSlashedIcon.tsx`,
`packages/uikit/src/components/Svg/Icons/LinkPlusIcon.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/Achievement.tsx`,
`apps/web/src/components/CrossChainVeCakeModal/hooks/useMultichainVeCakeWellSynced.ts`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/ContributeButton.tsx`,
`apps/web/src/views/Ifos/components/IfoFoldableCard/IfoPoolCard/ContributeModal.tsx`,
`apps/web/src/views/Home/components/Banners/EigenpieIFOBanner.tsx`,
`apps/web/src/views/Ifos/components/IfoSteps.tsx`,
`packages/localization/src/config/translations.json`,
`packages/widgets-internal/ifo/ChainLogo.tsx`,
`apps/web/src/views/Ifos/components/CrossChainVeCakeCard.tsx`,
`apps/web/src/components/CrossChainVeCakeModal/index.tsx`

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

<!-- end pr-codex -->
  • Loading branch information
thechefpenguin authored Sep 18, 2024
1 parent 2d352bf commit dbfa841
Show file tree
Hide file tree
Showing 50 changed files with 1,727 additions and 269 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { useQuery } from '@tanstack/react-query'
import { FAST_INTERVAL } from 'config/constants'

export type CrossChainStatus = CrossChainMessage['status']
export const useCrossChianMessage = (targetChainId?: ChainId, txHash?: string) => {
export const useCrossChainMessage = (targetChainId?: ChainId, txHash?: string) => {
const { data, isLoading } = useQuery({
queryKey: ['veCake/useCrossChianMessage', targetChainId, txHash],
queryKey: ['veCake/useCrossChainMessage', targetChainId, txHash],
queryFn: () => {
if (!txHash || !targetChainId) throw new Error('txHash and targetChainId are required')
return getCrossChainMessage({ chainId: targetChainId, txHash })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,38 @@ import { CROSS_CHAIN_CONFIG } from '../constants'

export const useMultichainVeCakeWellSynced = (
targetChainId?: ChainId,
targetTime?: number,
): {
isVeCakeWillSync?: boolean | null
isLoading: boolean
isVeCakeWillSync?: boolean | null
bscBalance?: bigint
bscProxyBalance?: bigint
targetChainBalance?: bigint
targetChainProxyBalance?: bigint
} => {
const { address: account } = useAccount()
const enabled = Boolean(account) && Boolean(targetChainId)
const { data, isLoading } = useQuery({
queryKey: [account, 'veCakeSyncData', targetChainId],
queryKey: [account, 'veCakeSyncData', targetChainId, targetTime],

queryFn: () => {
if (!account) throw new Error('account is required')
return getVCakeAndProxyData(account, targetChainId!)
return getVCakeAndProxyData(account, targetChainId!, targetTime)
},

enabled,
refetchInterval: FAST_INTERVAL,
staleTime: FAST_INTERVAL,
})
// return { isVeCakeWillSync: false, isLoading } // mock status
return { isVeCakeWillSync: data, isLoading }

return {
isVeCakeWillSync: data?.isVeCakeWillSync,
bscBalance: data?.bscBalance,
bscProxyBalance: data?.bscProxyBalance,
targetChainBalance: data?.targetChainBalance,
targetChainProxyBalance: data?.targetChainProxyBalance,
isLoading,
}
}

export const useAllMultichainSyncedCount = (): {
Expand Down Expand Up @@ -59,20 +71,20 @@ export const getAllMultichainSyncedCount = async (
const totalCount = queryChainList.length + 1 // add BSC CHAIN to count

const multichainIsWellSync = await Promise.all(
queryChainList.map((chainId) => getVCakeAndProxyData(address, chainId)),
queryChainList.map((chainId) => getVCakeAndProxyData(address, chainId).then((data) => data?.isVeCakeWillSync)),
)
return {
totalCount,
syncedCount: (multichainIsWellSync?.filter((isSync) => isSync === true)?.length ?? 0) + 1,
}
}

export const getVCakeAndProxyData = async (address: Address, targetChainId: ChainId): Promise<boolean | null> => {
export const getVCakeAndProxyData = async (address: Address, targetChainId: ChainId, targetTime?: number) => {
try {
const targetClient = publicClient({ chainId: targetChainId })
const bscClient = publicClient({ chainId: ChainId.BSC })

const targetTime = Math.floor(Date.now() / 1000) + 60
const finalTargetTime = targetTime || Math.floor(Date.now() / 1000) + 60

const [{ result: userInfo }] = await bscClient.multicall({
contracts: [
Expand All @@ -93,13 +105,13 @@ export const getVCakeAndProxyData = async (address: Address, targetChainId: Chai
address: getVeCakeAddress(ChainId.BSC),
abi: veCakeABI,
functionName: 'balanceOfAtTime',
args: [address, BigInt(targetTime)],
args: [address, BigInt(finalTargetTime)],
},
{
address: getVeCakeAddress(ChainId.BSC),
abi: veCakeABI,
functionName: 'balanceOfAtTime',
args: [userInfo?.[2], BigInt(targetTime)],
args: [userInfo?.[2], BigInt(finalTargetTime)],
},
],
})
Expand All @@ -110,13 +122,13 @@ export const getVCakeAndProxyData = async (address: Address, targetChainId: Chai
address: getVeCakeAddress(targetChainId),
abi: veCakeABI,
functionName: 'balanceOfAtTime',
args: [address, BigInt(targetTime)],
args: [address, BigInt(finalTargetTime)],
},
{
address: getVeCakeAddress(targetChainId),
abi: veCakeABI,
functionName: 'balanceOfAtTime',
args: [userInfo?.[2] ?? '0x0000000000000000000000000000000000000000', BigInt(targetTime)],
args: [userInfo?.[2] ?? '0x0000000000000000000000000000000000000000', BigInt(finalTargetTime)],
},
],
})
Expand All @@ -136,7 +148,7 @@ export const getVCakeAndProxyData = async (address: Address, targetChainId: Chai

const isVeCakeWillSync = bscBalance + bscProxyBalance === targetChainBalance + targetChainProxyBalance

return isVeCakeWillSync
return { isVeCakeWillSync, bscBalance, bscProxyBalance, targetChainBalance, targetChainProxyBalance }
} catch (e) {
console.error(e)
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { ChainId } from '@pancakeswap/chains'
import { useQuery } from '@tanstack/react-query'
import { pancakeProfileProxyABI } from 'config/abi/pancakeProfileProxy'
import { FAST_INTERVAL } from 'config/constants'
import useAccountActiveChain from 'hooks/useAccountActiveChain'
import { useActiveIfoConfig } from 'hooks/useIfoConfig'
import { useMemo } from 'react'
import { useProfile } from 'state/profile/hooks'
import { getPancakeProfileProxyAddress } from 'utils/addressHelpers'
Expand Down Expand Up @@ -78,20 +80,62 @@ export const useProfileProxy = (
return { profileProxy: data, isLoading: isPending }
}

export const getProfileProxyUserStatus = async (account?: Address, targetChainId?: ChainId) => {
if (!account || !targetChainId) return false

try {
const client = publicClient({ chainId: targetChainId })

// Returns a boolean indicating if profile is active or not
return client.readContract({
abi: pancakeProfileProxyABI,
address: getPancakeProfileProxyAddress(targetChainId),
functionName: 'getUserStatus',
args: [account],
})
} catch (e) {
console.error(e)
return false
}
}

export const useProfileProxyUserStatus = (account?: Address, targetChainId?: ChainId, enabled?: boolean) => {
const { account: localAccount, chainId: localChainId } = useAccountActiveChain()
const { data: isProfileActive } = useQuery({
queryKey: [account, 'profile-proxy-user-status'],
queryFn: () => getProfileProxyUserStatus(account ?? localAccount, targetChainId ?? localChainId),
enabled:
(enabled !== undefined ? enabled : true) && Boolean((account || localAccount) && (targetChainId || localChainId)),
refetchInterval: FAST_INTERVAL,
})

return {
isProfileActive: Boolean(isProfileActive),
}
}

export const useProfileProxyWellSynced = (targetChainId?: ChainId) => {
const { profile, isLoading } = useProfile()
const { profileProxy, isLoading: isProfileProxyLoading } = useProfileProxy(targetChainId)

// Check if IFO is active for this chain, only then check isProfileActive
const { activeIfo } = useActiveIfoConfig()
const isIfoActiveOnChain = useMemo(() => activeIfo?.chainId === targetChainId, [activeIfo, targetChainId])

const { isProfileActive } = useProfileProxyUserStatus(undefined, targetChainId, isIfoActiveOnChain)

const isSynced = useMemo(() => {
return (
!isLoading &&
!isProfileProxyLoading &&
(isIfoActiveOnChain ? isProfileActive : true) &&
profile?.tokenId === profileProxy?.tokenId &&
profile?.nft?.collectionAddress === profileProxy?.nftAddress &&
profile?.isActive === profileProxy?.isActive &&
profile?.points === profileProxy?.points &&
profile?.userId === profileProxy?.userId
)
}, [profile, profileProxy, isLoading, isProfileProxyLoading])
}, [profile, profileProxy, isLoading, isProfileProxyLoading, isProfileActive, isIfoActiveOnChain])

return { isLoading: isLoading || isProfileProxyLoading, isSynced }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ChainId } from '@pancakeswap/chains'
import { IfoChainId } from '@pancakeswap/widgets-internal/ifo/constants'
import { atom, useAtom } from 'jotai'

const txnByChainAtom = atom<Record<Exclude<IfoChainId, ChainId.BSC>, string>>({
[ChainId.ARBITRUM_ONE]: '',
[ChainId.ETHEREUM]: '',
[ChainId.ZKSYNC]: '',
})

export const useTxnByChain = () => {
return useAtom(txnByChainAtom)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ChainId } from '@pancakeswap/chains'
import { useMultichainVeCakeWellSynced } from 'components/CrossChainVeCakeModal/hooks/useMultichainVeCakeWellSynced'
import { useMemo } from 'react'
import { useProfileProxyWellSynced } from './useProfileProxyWellSynced'

export const useUserVeCakeStatus = (targetChainId?: ChainId, targetTime?: number) => {
const {
isVeCakeWillSync: isVeCakeSynced,
bscBalance,
bscProxyBalance,
targetChainBalance,
targetChainProxyBalance,
} = useMultichainVeCakeWellSynced(targetChainId, targetTime)

const { isSynced: isProfileSynced } = useProfileProxyWellSynced(targetChainId)

const isSynced = useMemo(() => Boolean(isVeCakeSynced && isProfileSynced), [isVeCakeSynced, isProfileSynced])

return {
isSynced,
isVeCakeSynced: Boolean(isVeCakeSynced),
isProfileSynced: Boolean(isProfileSynced),
bscBalance,
bscProxyBalance,
targetChainBalance,
targetChainProxyBalance,
}
}
Loading

0 comments on commit dbfa841

Please sign in to comment.