diff --git a/apps/web/src/state/predictions/helpers.ts b/apps/web/src/state/predictions/helpers.ts index e44bf0db18072..0863e555289cc 100644 --- a/apps/web/src/state/predictions/helpers.ts +++ b/apps/web/src/state/predictions/helpers.ts @@ -407,7 +407,10 @@ export const makeLedgerData = (account: string, ledgers: PredictionsLedgerRespon /** * Serializes the return from the "rounds" call for redux */ -export const serializePredictionsRoundsResponse = (response: PredictionsRoundsResponse): ReduxNodeRound => { +export const serializePredictionsRoundsResponse = ( + response: PredictionsRoundsResponse, + chainId: ChainId, +): ReduxNodeRound => { const { epoch, startTimestamp, @@ -425,14 +428,23 @@ export const serializePredictionsRoundsResponse = (response: PredictionsRoundsRe closeOracleId, } = response + let lockPriceAmount = lockPrice === 0n ? null : lockPrice.toString() + let closePriceAmount = closePrice === 0n ? null : closePrice.toString() + + // Chainlink in ARBITRUM lockPrice & closePrice will return 18 decimals, other chain is return 8 decimals. + if (chainId === ChainId.ARBITRUM_ONE) { + lockPriceAmount = lockPrice === 0n ? null : (Number(lockPrice) / Number(1e10)).toFixed() + closePriceAmount = closePrice === 0n ? null : (Number(closePrice) / Number(1e10)).toFixed() + } + return { oracleCalled, epoch: Number(epoch), startTimestamp: startTimestamp === 0n ? null : Number(startTimestamp), lockTimestamp: lockTimestamp === 0n ? null : Number(lockTimestamp), closeTimestamp: closeTimestamp === 0n ? null : Number(closeTimestamp), - lockPrice: lockPrice === 0n ? null : lockPrice.toString(), - closePrice: closePrice === 0n ? null : closePrice.toString(), + lockPrice: lockPriceAmount, + closePrice: closePriceAmount, totalAmount: totalAmount.toString(), bullAmount: bullAmount.toString(), bearAmount: bearAmount.toString(), diff --git a/apps/web/src/state/predictions/index.ts b/apps/web/src/state/predictions/index.ts index 428fb186ac686..d2257e8466d2c 100644 --- a/apps/web/src/state/predictions/index.ts +++ b/apps/web/src/state/predictions/index.ts @@ -99,7 +99,7 @@ export const fetchPredictionData = createAsyncThunk< // Round data const roundsResponse = await getRoundsData(epochs, extra.address, chainId) const initialRoundData: { [key: string]: ReduxNodeRound } = roundsResponse.reduce((accum, roundResponse) => { - const reduxNodeRound = serializePredictionsRoundsResponse(roundResponse) + const reduxNodeRound = serializePredictionsRoundsResponse(roundResponse, chainId) return { ...accum, @@ -181,8 +181,14 @@ export const fetchNodeHistory = createAsyncThunk< const bets: Bet[] = roundData.reduce((accum: any, round: PredictionsRoundsResponse) => { const ledger = userRounds[Number(round.epoch)] const ledgerAmount = BigInt(ledger.amount) - const closePrice = round.closePrice ? parseFloat(formatUnits(round.closePrice, 8)) : null - const lockPrice = round.lockPrice ? parseFloat(formatUnits(round.lockPrice, 8)) : null + let closePrice = round.closePrice ? parseFloat(formatUnits(round.closePrice, 8)) : null + let lockPrice = round.lockPrice ? parseFloat(formatUnits(round.lockPrice, 8)) : null + + // Chainlink in ARBITRUM lockPrice & closePrice will return 18 decimals, other chain is return 8 decimals. + if (chainId === ChainId.ARBITRUM_ONE && (round.closePrice || round.lockPrice)) { + closePrice = parseFloat(formatUnits(round.closePrice, 18)) + lockPrice = parseFloat(formatUnits(round.lockPrice, 18)) + } const getRoundPosition = () => { if (!closePrice) { diff --git a/apps/web/src/views/Predictions/Leaderboard/index.tsx b/apps/web/src/views/Predictions/Leaderboard/index.tsx index 415e7f1fd0bb4..6a18be3f13dcb 100644 --- a/apps/web/src/views/Predictions/Leaderboard/index.tsx +++ b/apps/web/src/views/Predictions/Leaderboard/index.tsx @@ -20,6 +20,7 @@ const Leaderboard = () => { const { address: account } = useAccount() const filters = useGetLeaderboardFilters() const leaderboardLoadingState = useGetLeaderboardLoadingState() + const [isFirstTime, setIsFirstTime] = useState(true) const [pickedChainId, setPickedChainId] = useState(ChainId.BSC) const [pickedTokenSymbol, setPickedTokenSymbol] = useState(PredictionSupportedSymbol.BNB) const predictionConfigs = usePredictionConfigs(pickedChainId) @@ -40,15 +41,16 @@ const Leaderboard = () => { : (Object.values(predictionConfigs)?.[0]?.token?.symbol as PredictionSupportedSymbol) setPickedTokenSymbol(defaultPickedTokenSymbol) + setIsFirstTime(false) } }, [query, predictionConfigs, pickedChainId]) useEffect(() => { - if (predictionConfigs) { + if (predictionConfigs && !isFirstTime) { const extra = predictionConfigs?.[pickedTokenSymbol] ?? Object.values(predictionConfigs)?.[0] dispatch(filterLeaderboard({ filters, extra })) } - }, [account, filters, dispatch, predictionConfigs, pickedChainId, pickedTokenSymbol]) + }, [isFirstTime, account, filters, dispatch, predictionConfigs, pickedChainId, pickedTokenSymbol]) if (leaderboardLoadingState === FetchStatus.Idle) { return diff --git a/apps/web/src/views/Predictions/components/ChainlinkChart.tsx b/apps/web/src/views/Predictions/components/ChainlinkChart.tsx index 8e0b9c45e1bb4..3fed19047003d 100644 --- a/apps/web/src/views/Predictions/components/ChainlinkChart.tsx +++ b/apps/web/src/views/Predictions/components/ChainlinkChart.tsx @@ -146,6 +146,7 @@ const HoverData = ({ rounds }: { rounds: { [key: string]: NodeRound } }) => { flexWrap="wrap" alignItems="center" columnGap="12px" + zIndex={2} > {hoverData && ( diff --git a/apps/web/src/views/Predictions/components/Menu.tsx b/apps/web/src/views/Predictions/components/Menu.tsx index c6048afc3e438..cde119c30c8a3 100644 --- a/apps/web/src/views/Predictions/components/Menu.tsx +++ b/apps/web/src/views/Predictions/components/Menu.tsx @@ -16,7 +16,7 @@ import PrevNextNav from './PrevNextNav' const SetCol = styled.div` position: relative; flex: none; - width: auto; + width: 170px; ${({ theme }) => theme.mediaQueries.lg} { width: 270px; diff --git a/apps/web/src/views/Predictions/components/RoundCard/LiveRoundCard.tsx b/apps/web/src/views/Predictions/components/RoundCard/LiveRoundCard.tsx index e464f43e9ff0d..6225cf7562952 100644 --- a/apps/web/src/views/Predictions/components/RoundCard/LiveRoundCard.tsx +++ b/apps/web/src/views/Predictions/components/RoundCard/LiveRoundCard.tsx @@ -124,7 +124,11 @@ const LiveRoundCard: React.FC> = ({
- +
{formatUsdv2(priceDifference, config?.displayedDecimals ?? 0)} diff --git a/apps/web/src/views/Predictions/components/RoundCard/LiveRoundPrice.tsx b/apps/web/src/views/Predictions/components/RoundCard/LiveRoundPrice.tsx index b3dd8c023d2a6..9f82dfea0ba63 100644 --- a/apps/web/src/views/Predictions/components/RoundCard/LiveRoundPrice.tsx +++ b/apps/web/src/views/Predictions/components/RoundCard/LiveRoundPrice.tsx @@ -1,15 +1,20 @@ -import React, { memo, useMemo } from 'react' -import CountUp from 'react-countup' +import { BetPosition } from '@pancakeswap/prediction' import { Skeleton, TooltipText } from '@pancakeswap/uikit' import { formatBigIntToFixed } from '@pancakeswap/utils/formatBalance' -import { BetPosition } from '@pancakeswap/prediction' +import React, { memo, useMemo } from 'react' +import CountUp from 'react-countup' interface LiveRoundPriceProps { + displayedDecimals: number betPosition: BetPosition price: bigint } -const LiveRoundPrice: React.FC> = ({ betPosition, price }) => { +const LiveRoundPrice: React.FC> = ({ + displayedDecimals, + betPosition, + price, +}) => { const priceAsNumber = useMemo(() => parseFloat(formatBigIntToFixed(price, 4, 8)), [price]) const priceColor = useMemo(() => { @@ -33,7 +38,7 @@ const LiveRoundPrice: React.FC> = ( } return ( - + {({ countUpRef }) => ( diff --git a/apps/web/src/views/Predictions/components/RoundCard/SetPositionCard.tsx b/apps/web/src/views/Predictions/components/RoundCard/SetPositionCard.tsx index dd44f9c182ef6..5ebd0a48f71c3 100644 --- a/apps/web/src/views/Predictions/components/RoundCard/SetPositionCard.tsx +++ b/apps/web/src/views/Predictions/components/RoundCard/SetPositionCard.tsx @@ -111,7 +111,7 @@ const SetPositionCard: React.FC> = }, [isNativeToken, userNativeTokenBalance, userBalance]) const maxBalance = useMemo(() => (balance > dust ? balance - dust : 0n), [balance]) - const balanceDisplay = formatBigInt(balance) + const balanceDisplay = formatBigInt(balance, config?.token?.decimals, config?.token?.decimals) const valueAsBn = getValueAsEthersBn(value) const showFieldWarning = account && valueAsBn > 0n && errorMessage !== null diff --git a/apps/web/src/views/Predictions/components/TokenSelector/Desktop.tsx b/apps/web/src/views/Predictions/components/TokenSelector/Desktop.tsx index 5284791fd7ac1..18853af33555b 100644 --- a/apps/web/src/views/Predictions/components/TokenSelector/Desktop.tsx +++ b/apps/web/src/views/Predictions/components/TokenSelector/Desktop.tsx @@ -57,6 +57,7 @@ export const DesktopPredictionTokenSelector: React.FC diff --git a/apps/web/src/views/Predictions/components/TokenSelector/Mobile.tsx b/apps/web/src/views/Predictions/components/TokenSelector/Mobile.tsx index 5dd97f3638db8..dc7105f142395 100644 --- a/apps/web/src/views/Predictions/components/TokenSelector/Mobile.tsx +++ b/apps/web/src/views/Predictions/components/TokenSelector/Mobile.tsx @@ -34,6 +34,7 @@ export const MobilePredictionTokenSelector: React.FC @@ -62,6 +63,7 @@ export const MobilePredictionTokenSelector: React.FC{`${list?.token?.symbol}USD`}
diff --git a/apps/web/src/views/Predictions/components/TokenSelector/Price.tsx b/apps/web/src/views/Predictions/components/TokenSelector/Price.tsx index 2c7b2705f57e9..39fbc46f1ddbb 100644 --- a/apps/web/src/views/Predictions/components/TokenSelector/Price.tsx +++ b/apps/web/src/views/Predictions/components/TokenSelector/Price.tsx @@ -6,11 +6,13 @@ import { Address } from 'viem' import usePollOraclePrice from 'views/Predictions/hooks/usePollOraclePrice' interface PriceProps extends TextProps { + displayedDecimals?: number chainlinkOracleAddress?: Address galetoOracleAddress?: Address } export const Price: React.FC> = ({ + displayedDecimals, chainlinkOracleAddress, galetoOracleAddress, ...props @@ -27,7 +29,7 @@ export const Price: React.FC> = ({ } return ( - + {({ countUpRef }) => ( diff --git a/apps/web/src/views/Predictions/components/TokenSelector/index.tsx b/apps/web/src/views/Predictions/components/TokenSelector/index.tsx index 06530ec0d25a0..41feb979b7eaa 100644 --- a/apps/web/src/views/Predictions/components/TokenSelector/index.tsx +++ b/apps/web/src/views/Predictions/components/TokenSelector/index.tsx @@ -128,6 +128,7 @@ export const TokenSelector = () => { diff --git a/packages/prediction/src/chainlinkOracleContract.ts b/packages/prediction/src/chainlinkOracleContract.ts index 263ab2d85e843..bab8ec4277239 100644 --- a/packages/prediction/src/chainlinkOracleContract.ts +++ b/packages/prediction/src/chainlinkOracleContract.ts @@ -6,14 +6,23 @@ import { ContractAddresses } from './type' export const chainlinkOracleBNB: Record = { [ChainId.BSC]: '0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE', [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x', } as const satisfies ContractAddresses export const chainlinkOracleCAKE: Record = { [ChainId.BSC]: '0xB6064eD41d4f67e353768aA239cA86f4F73665a1', [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x', } as const satisfies ContractAddresses export const chainlinkOracleETH: Record = { [ChainId.BSC]: '0x', [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612', +} as const satisfies ContractAddresses + +export const chainlinkOracleWBTC: Record = { + [ChainId.BSC]: '0x', + [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x6ce185860a4963106506C203335A2910413708e9', } as const satisfies ContractAddresses diff --git a/packages/prediction/src/constants/config.ts b/packages/prediction/src/constants/config.ts index 4ea5eeb8472d7..409bf1582b8e5 100644 --- a/packages/prediction/src/constants/config.ts +++ b/packages/prediction/src/constants/config.ts @@ -15,4 +15,5 @@ export const LEADERBOARD_MIN_ROUNDS_PLAYED = { [PredictionSupportedSymbol.BNB]: 10, [PredictionSupportedSymbol.CAKE]: 10, [PredictionSupportedSymbol.ETH]: 0, + [PredictionSupportedSymbol.WBTC]: 0, } as const satisfies LeaderboardMinRoundsPlatedType diff --git a/packages/prediction/src/constants/predictions/arb.ts b/packages/prediction/src/constants/predictions/arb.ts index 2d15319efae2b..83df5ae23eefb 100644 --- a/packages/prediction/src/constants/predictions/arb.ts +++ b/packages/prediction/src/constants/predictions/arb.ts @@ -1,3 +1,28 @@ -import { PredictionConfig } from '../../type' +import { ChainId } from '@pancakeswap/chains' +import { Native } from '@pancakeswap/sdk' +// import { arbitrumTokens } from '@pancakeswap/tokens' +import { chainlinkOracleETH } from '../../chainlinkOracleContract' +import { GRAPH_API_PREDICTION_ETH } from '../../endpoints' +import { predictionsETH } from '../../predictionContract' +import { PredictionConfig, PredictionSupportedSymbol } from '../../type' -export const predictions: Record = {} +export const predictions: Record = { + [PredictionSupportedSymbol.ETH]: { + isNativeToken: true, + address: predictionsETH[ChainId.ARBITRUM_ONE], + api: GRAPH_API_PREDICTION_ETH[ChainId.ARBITRUM_ONE], + chainlinkOracleAddress: chainlinkOracleETH[ChainId.ARBITRUM_ONE], + displayedDecimals: 4, + token: Native.onChain(ChainId.ARBITRUM_ONE), + tokenBackgroundColor: '#647ceb', + }, + // [PredictionSupportedSymbol.WBTC]: { + // isNativeToken: false, + // address: predictionsWBTC[ChainId.ARBITRUM_ONE], + // api: GRAPH_API_PREDICTION_WBTC[ChainId.ARBITRUM_ONE], + // chainlinkOracleAddress: chainlinkOracleWBTC[ChainId.ARBITRUM_ONE], + // displayedDecimals: 4, + // token: arbitrumTokens.wbtc, + // tokenBackgroundColor: '#F7931A', + // }, +} diff --git a/packages/prediction/src/constants/supportedChains.ts b/packages/prediction/src/constants/supportedChains.ts index 7ee9c44f0a95f..67ec8d50e70ad 100644 --- a/packages/prediction/src/constants/supportedChains.ts +++ b/packages/prediction/src/constants/supportedChains.ts @@ -1,8 +1,8 @@ import { ChainId } from '@pancakeswap/chains' -import { bsc, zkSync } from 'wagmi/chains' +import { arbitrum, bsc, zkSync } from 'wagmi/chains' -export const SUPPORTED_CHAIN_IDS = [ChainId.BSC, ChainId.ZKSYNC] as const +export const SUPPORTED_CHAIN_IDS = [ChainId.BSC, ChainId.ZKSYNC, ChainId.ARBITRUM_ONE] as const export type SupportedChainId = (typeof SUPPORTED_CHAIN_IDS)[number] -export const targetChains = [bsc, zkSync] +export const targetChains = [bsc, zkSync, arbitrum] diff --git a/packages/prediction/src/endpoints.ts b/packages/prediction/src/endpoints.ts index 53ec8e1aece52..4b192506b1525 100644 --- a/packages/prediction/src/endpoints.ts +++ b/packages/prediction/src/endpoints.ts @@ -5,14 +5,23 @@ import { EndPointType } from './type' export const GRAPH_API_PREDICTION_BNB = { [ChainId.BSC]: 'https://api.thegraph.com/subgraphs/name/pancakeswap/prediction-v2', [ChainId.ZKSYNC]: '', + [ChainId.ARBITRUM_ONE]: '', } as const satisfies EndPointType export const GRAPH_API_PREDICTION_CAKE = { [ChainId.BSC]: 'https://api.thegraph.com/subgraphs/name/pancakeswap/prediction-cake', [ChainId.ZKSYNC]: '', + [ChainId.ARBITRUM_ONE]: '', } as const satisfies EndPointType export const GRAPH_API_PREDICTION_ETH = { [ChainId.BSC]: '', [ChainId.ZKSYNC]: 'https://api.studio.thegraph.com/query/48759/prediction-v2-zksync-era/version/latest', + [ChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/pancakeswap/prediction-v2-arbitrum', +} as const satisfies EndPointType + +export const GRAPH_API_PREDICTION_WBTC = { + [ChainId.BSC]: '', + [ChainId.ZKSYNC]: '', + [ChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/pancakeswap/prediction-v2-arbitrum-wbtc', } as const satisfies EndPointType diff --git a/packages/prediction/src/galetoOracleContract.ts b/packages/prediction/src/galetoOracleContract.ts index 4f2168b946869..f8d55aeee0e8e 100644 --- a/packages/prediction/src/galetoOracleContract.ts +++ b/packages/prediction/src/galetoOracleContract.ts @@ -6,4 +6,5 @@ import { ContractAddresses } from './type' export const galetoOracleETH: Record = { [ChainId.BSC]: '0x', [ChainId.ZKSYNC]: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace', + [ChainId.ARBITRUM_ONE]: '0x', } as const satisfies ContractAddresses diff --git a/packages/prediction/src/predictionContract.ts b/packages/prediction/src/predictionContract.ts index 77e2323071df8..859d1237f7681 100644 --- a/packages/prediction/src/predictionContract.ts +++ b/packages/prediction/src/predictionContract.ts @@ -6,14 +6,23 @@ import { ContractAddresses } from './type' export const predictionsBNB: Record = { [ChainId.BSC]: '0x18B2A687610328590Bc8F2e5fEdDe3b582A49cdA', [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x', } as const satisfies ContractAddresses export const predictionsCAKE: Record = { [ChainId.BSC]: '0x0E3A8078EDD2021dadcdE733C6b4a86E51EE8f07', [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x', } as const satisfies ContractAddresses export const predictionsETH: Record = { [ChainId.BSC]: '0x', [ChainId.ZKSYNC]: '0x43c7771DEB958A2e3198ED98772056ba70DaA84c', + [ChainId.ARBITRUM_ONE]: '0xF2F90E718a3BFaCb430c1818cB962f05A2631998', +} as const satisfies ContractAddresses + +export const predictionsWBTC: Record = { + [ChainId.BSC]: '0x', + [ChainId.ZKSYNC]: '0x', + [ChainId.ARBITRUM_ONE]: '0x870CBfD72970E6ad146310Dd0EC546Db1Cbbe6F8', } as const satisfies ContractAddresses diff --git a/packages/prediction/src/type.ts b/packages/prediction/src/type.ts index 21b0f3b42641c..0cc03b09d8f67 100644 --- a/packages/prediction/src/type.ts +++ b/packages/prediction/src/type.ts @@ -7,6 +7,7 @@ export enum PredictionSupportedSymbol { BNB = 'BNB', CAKE = 'CAKE', ETH = 'ETH', + WBTC = 'WBTC', } export enum BetPosition {