diff --git a/apps/bridge/components/Menu.tsx b/apps/bridge/components/Menu.tsx index d11e6ccf49e31..66c9a208b700a 100644 --- a/apps/bridge/components/Menu.tsx +++ b/apps/bridge/components/Menu.tsx @@ -1,34 +1,8 @@ -import { CurrencyAmount, Token } from '@pancakeswap/sdk' -import { - BlockIcon, - Box, - Button, - CheckmarkCircleIcon, - Flex, - Link, - Logo, - Modal, - OpenNewIcon, - RefreshIcon, - Text, - ThemeSwitcher, - useModal, - UserMenu, - UserMenuDivider, - UserMenuItem, - DropdownMenuItemType, - DropdownMenu, - useMatchBreakpoints, -} from '@pancakeswap/uikit' +import { Box, Flex, Logo, ThemeSwitcher, DropdownMenuItemType, DropdownMenu } from '@pancakeswap/uikit' import { useRouter } from 'next/router' import { useTheme as useNextTheme } from 'next-themes' -import Image from 'next/image' import NextLink from 'next/link' -import { useEffect, useReducer, useRef, useState } from 'react' import styled, { useTheme } from 'styled-components' -import getTimePeriods from '@pancakeswap/utils/getTimePeriods' -import { CHAINS_STARGATE } from './stargate/config' -import { findChainByStargateId } from './stargate/network' const StyledMenuItem = styled('div')<{ $isActive?: boolean }>` position: relative; @@ -52,31 +26,6 @@ const StyledMenuItem = styled('div')<{ $isActive?: boolean }>` } ` -const TxnIcon = styled(Flex)` - align-items: center; - flex: none; - width: 24px; -` - -const Summary = styled(Flex)` - flex: 1; - align-items: center; - padding: 0 8px; - gap: 4px; -` - -const TxnLink = styled(Link)` - align-items: center; - color: ${({ theme }) => theme.colors.text}; - display: flex; - margin-bottom: 16px; - width: 100%; - - &:hover { - text-decoration: none; - } -` - const MenuConfig = [ { title: 'CAKE', href: '/' }, { @@ -95,12 +44,8 @@ const MenuConfig = [ }, { title: 'Aptos', - href: '/aptos', + href: '/', items: [ - { - label: 'Pancake Bridge', - href: '/aptos', - }, { label: 'LayerZero', href: 'https://theaptosbridge.com/bridge', @@ -161,303 +106,7 @@ export function Menu() { setTheme(theme.isDark ? 'light' : 'dark')} /> - {nextRouter.pathname === '/stargate' && } ) } - -const UserMenuItems = ({ onShowTx }: { onShowTx: () => void }) => { - return ( - <> - - Recent Transactions - - - - Select a Network - - - {CHAINS_STARGATE.map((chain) => ( - switchNetwork(chain.id)}> - {`chain-${chain.name}`} - {chain.name} - - ))} - - window?.stargate.wallet.disconnect()}> - Disconnect - - - ) -} - -async function switchNetwork(chainId: number) { - const chain = CHAINS_STARGATE.find((c) => c.id === chainId) - const provider = window?.stargate?.wallet?.ethereum?.signer?.provider?.provider ?? (window as any)?.ethereum - if (chain && provider) { - try { - await provider.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: `0x${chainId.toString(16)}` }], - }) - return true - } catch (switchError) { - if ((switchError as any)?.code === 4902) { - try { - await provider.request({ - method: 'wallet_addEthereumChain', - params: [ - { - chainId: chain.id, - chainName: chain.name, - nativeCurrency: chain.nativeCurrency, - rpcUrls: chain.rpcUrls.default, - blockExplorerUrls: chain.blockExplorers?.default, - }, - ], - }) - return true - } catch (error) { - console.error('Failed to setup the network', error) - return false - } - } - return false - } - } - return false -} - -function useStargateReaction(expression: () => T) { - const savedExpression = useRef(expression) - const [value, setValue] = useState() - - useEffect(() => { - savedExpression.current = expression - }, [expression]) - - useEffect(() => { - customElements.whenDefined('stargate-widget').then(() => { - setValue(savedExpression.current) - window?.stargate?.utils?.reaction(savedExpression.current, (v: T) => { - setValue(v) - }) - }) - }, []) - - return value -} - -const renderIcon = (txn: TransactionType) => { - if (!txn.completed) { - return - } - - if (txn.error) { - return - } - - return -} - -function RecentTransactionsModal({ - onDismiss, - transactions, -}: { - onDismiss?: () => void - transactions: TransactionType[] -}) { - return ( - - - - - {transactions?.map((txn, i) => { - const txnChain = findChainByStargateId(txn.chainId) - return ( - - {renderIcon(txn)} - - {txn.type === 'APPROVE' && ( - <> - {`Approve ${txn?.input?.amount?.currency?.symbol ?? ''}`}{' '} - {`${txnChain?.chain?.name}`} - - )} - {txn.type === 'TRANSFER' && ( - <> - Transfer {txn.input.amount.toSignificant(2)} {txn.input.from.token.symbol} - {`chain-${findChainByStargateId(txn?.input?.from?.chainId)?.chain?.name}`} - to {txn.input.to.token.symbol}{' '} - {`chain-${findChainByStargateId(txn?.input?.to?.chainId)?.chain?.name}`} - - )} - - - {txn.type === 'TRANSFER' && !txn.completed && txn.expected && } - - - - - - ) - })} - - ) -} - -function CountDown({ expected }: { expected: string }) { - const secondLeft = (Date.now() - new Date(expected).getTime()) / 1000 - const { hours, minutes, seconds } = getTimePeriods(secondLeft) - const [, forceUpdate] = useReducer((s) => s + 1, 0) - - useEffect(() => { - setInterval(() => forceUpdate(), 1000) - }, []) - - if (secondLeft > 0) { - return null - } - - return ( - - {hours ? `${hours} h` : null} {hours || minutes ? `${minutes} m` : null} {`${parseInt(String(seconds))} s`} - - ) -} - -type BaseTxnType = { - chainId: number - progress: number - completed: boolean - hash: string - expected: string // date - exceeded: boolean - submitted: string // date - confirmations: number - confirmation?: { - hash: string - chainId: number - } - error?: any // ?? -} - -type TransactionApprove = { - type: 'APPROVE' - input: { - amount: CurrencyAmount - spender: string - account: string - } -} & BaseTxnType - -type TransactionTransfer = { - type: 'TRANSFER' - input: TransferInput -} & BaseTxnType - -type TransactionType = TransactionApprove | TransactionTransfer - -type TransferInput = { - from: { - account: string - chainId: number - token: Token - } - to: { - account: string - chainId: number - token: Token - } - amount: CurrencyAmount - minAmount: CurrencyAmount - nativeFee: CurrencyAmount - dstNativeAmount: CurrencyAmount -} - -function User() { - const { isMobile } = useMatchBreakpoints() - const wallet = useStargateReaction(() => window.stargate.wallet.ethereum) - const [pending, setPending] = useState([]) - const transactions = useStargateReaction(() => window.stargate.transaction.transactions) - const [showRecentTxModal] = useModal(, true, true, 'recent-tx') - - useEffect(() => { - customElements.whenDefined('stargate-widget').then(() => { - setInterval(() => { - setPending(window.stargate.transaction.pickPendingTransactions()) - }, 1000) - }) - }, []) - - const { account, chainId } = wallet || {} - - const chain = findChainByStargateId(chainId) - - const isWrongNetwork = chainId && !chain - const hasPendingTransactions = pending.length > 0 - - if (isMobile && !account) { - return null - } - - if (isWrongNetwork) { - return ( - - {() => showRecentTxModal()} />} - - ) - } - - if (account) { - return ( - - {() => showRecentTxModal()} />} - - ) - } - - return ( - - ) -} diff --git a/apps/bridge/components/layerZero/LayerZeroWidget.tsx b/apps/bridge/components/layerZero/LayerZeroWidget.tsx index aaf7c2586b767..ccd0b28c7bbd4 100644 --- a/apps/bridge/components/layerZero/LayerZeroWidget.tsx +++ b/apps/bridge/components/layerZero/LayerZeroWidget.tsx @@ -1,10 +1,9 @@ import { useEffect } from 'react' import { Box, PancakeTheme } from '@pancakeswap/uikit' -import { darkTheme, lightTheme } from 'components/layerZero/theme' declare global { interface Window { - aptosBridge?: any + app?: any } interface Document { querySelector?: any @@ -14,79 +13,33 @@ declare global { export const LayerZeroWidget = ({ theme }: { theme: PancakeTheme }) => { useEffect(() => { const themeText = theme.isDark ? 'dark' : 'light' - const themeColor = theme.isDark ? darkTheme : lightTheme - if (window.aptosBridge) { + const fetch = async () => { + const app: any = await customElements.whenDefined('lz-bridge') document.body.classList.add(themeText) - document.querySelector('aptos-bridge').setTheme(themeColor) + const themeColor = theme.isDark ? app?.uiStore?.theme?.config?.dark : app?.uiStore?.theme?.config?.light + app?.uiStore?.theme?.setTheme?.(themeColor) } - return () => { - document.body.classList.remove(themeText) - } + fetch() }, [theme]) return ( {/* @ts-ignore */} - + + {/* @ts-ignore */} + ) } diff --git a/apps/bridge/components/layerZero/config.ts b/apps/bridge/components/layerZero/config.ts index 1cbbaac14fbb4..53b32ca34df2b 100644 --- a/apps/bridge/components/layerZero/config.ts +++ b/apps/bridge/components/layerZero/config.ts @@ -1,7 +1,13 @@ -const VERSION = '0.0.0-alpha.27-mainnet.10' -const SHA384 = 'EoecksQ6B3PYYmi2Qmtx0m0cfnIijDdc3XGCHbRkzO8ekpvHdITE3fNxTEVmUCTW' +const VERSION = '0.0.19' +// https://unpkg.com/@layerzerolabs/x-pancakeswap-widget@0.0.19/element.mjs.sha384 +const SHA384 = 'vFsGllKrtj0a3Zmmbv9/oOUXwg5KRwOmB2Cxd82TA+iVK1rzBkC4RjQcg/tBjUrK' export const LAYER_ZERO_JS = { - src: `https://unpkg.com/@layerzerolabs/aptos-bridge-widget@${VERSION}/element.js`, + src: `https://unpkg.com/@layerzerolabs/x-pancakeswap-widget@${VERSION}/element.mjs`, + css: `https://unpkg.com/@layerzerolabs/x-pancakeswap-widget@${VERSION}/element.css`, integrity: `sha384-${SHA384}`, } + +export const PARTNER_ID = 0x0002 +export const FEE_COLLECTOR = '0x68C7ABB8b1c3D1cE467E28265770F3a7ECF32654' +export const FEE_TENTH_BPS = '0' diff --git a/apps/bridge/components/layerZero/index.tsx b/apps/bridge/components/layerZero/index.tsx new file mode 100644 index 0000000000000..294412675cef7 --- /dev/null +++ b/apps/bridge/components/layerZero/index.tsx @@ -0,0 +1,98 @@ +import { useEffect, useState } from 'react' +import Script from 'next/script' +import styled, { useTheme } from 'styled-components' +import { Flex, Box } from '@pancakeswap/uikit' +import { LAYER_ZERO_JS, FEE_COLLECTOR, FEE_TENTH_BPS, PARTNER_ID } from 'components/layerZero/config' +import { LayerZeroWidget } from 'components/layerZero/LayerZeroWidget' +import AptosBridgeFooter from 'components/layerZero/AptosBridgeFooter' +import { PancakeSwapTheme } from './theme' + +declare global { + interface Window { + app?: any + } +} + +const Page = styled(Box)` + display: flex; + height: 100%; + height: calc(100vh - 56px); + background: ${({ theme }) => theme.colors.backgroundAlt}; + + ${({ theme }) => theme.mediaQueries.sm} { + min-height: 1000px; + background: ${({ theme }) => theme.colors.gradientBubblegum}; + } +` + +const LayerZero = ({ isCake }: { isCake?: boolean }) => { + const theme = useTheme() + const [show, setShow] = useState(false) + + useEffect(() => { + customElements.whenDefined('lz-bridge').then((Bridge: any) => { + const { createBasicTheme, bootstrap, uiStore } = Bridge + + if (!Bridge.initialized) { + bootstrap({ + stargate: { + partner: { + partnerId: PARTNER_ID, + feeCollector: FEE_COLLECTOR, + feeBps: FEE_TENTH_BPS, + }, + }, + }) + + const newTheme = { + dark: createBasicTheme(PancakeSwapTheme.dark), + light: createBasicTheme(PancakeSwapTheme.light), + } + uiStore.theme.setConfig(newTheme) + } + + if (isCake) { + setTimeout(async () => { + const app: any = await customElements.whenDefined('lz-bridge') + const length = app?.bridgeStore?.currencies?.length + if (length !== null || length !== undefined) { + const currencies = app?.bridgeStore?.currencies?.slice() + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + app!.bridgeStore!.currencies.length = 0 + app?.bridgeStore?.addCurrencies(currencies?.filter((i) => i.symbol.toLowerCase() === 'cake')) + + const srcCake = app?.bridgeStore?.currencies?.find( + (i) => i.symbol.toUpperCase() === 'CAKE' && i.chainId === 102, + ) + app?.bridgeStore?.setSrcCurrency(srcCake) + } + }, 800) + } + + setShow(true) + }) + }, [isCake]) + + return ( + +