diff --git a/packages/widget/src/components/BridgeButton.tsx b/packages/widget/src/components/BridgeButton.tsx index a6609c8abf..d5a79d15fd 100644 --- a/packages/widget/src/components/BridgeButton.tsx +++ b/packages/widget/src/components/BridgeButton.tsx @@ -14,6 +14,7 @@ interface BridgeButtonProps { handleBridge: () => any isApprovalPending: boolean isBridgePending: boolean + isBridgePaused: boolean } export const BridgeButton = ({ @@ -23,6 +24,7 @@ export const BridgeButton = ({ handleBridge, isApprovalPending, isBridgePending, + isBridgePaused, }: BridgeButtonProps) => { const web3Context = useContext(Web3Context) @@ -52,6 +54,14 @@ export const BridgeButton = ({ const tooltipPositionStyle = '-top-8' + if (isBridgePaused) { + return ( + + Bridge paused + + ) + } + if (!provider || !connectedAddress) { return ( diff --git a/packages/widget/src/components/Maintenance/EventCountdownProgressBar.tsx b/packages/widget/src/components/Maintenance/EventCountdownProgressBar.tsx new file mode 100644 index 0000000000..6912ef77a0 --- /dev/null +++ b/packages/widget/src/components/Maintenance/EventCountdownProgressBar.tsx @@ -0,0 +1,45 @@ +import { isNull } from 'lodash' + +import { LinearAnimatedProgressBar } from './LinearAnimatedProgressBar' + +export const EventCountdownProgressBar = ({ + eventLabel, + startDate, + endDate, + timeRemaining, + status, +}: { + eventLabel: string + startDate: Date + endDate: Date | null + timeRemaining: string + status: 'idle' | 'pending' | 'complete' +}) => { + const isIndefinite = isNull(endDate) + + if (status === 'pending') { + return ( + + + {eventLabel} + {isIndefinite ? null : {timeRemaining} remaining} + + + + + + ) + } else { + return null + } +} diff --git a/packages/widget/src/components/Maintenance/LinearAnimatedProgressBar.tsx b/packages/widget/src/components/Maintenance/LinearAnimatedProgressBar.tsx new file mode 100644 index 0000000000..54cb234452 --- /dev/null +++ b/packages/widget/src/components/Maintenance/LinearAnimatedProgressBar.tsx @@ -0,0 +1,179 @@ +import { memo } from 'react' +import { isNull } from 'lodash' + +import { getCountdownTimeStatus } from '@/utils/getCountdownTimeStatus' + +/** + * Constructs animated progress bar visualizing time progress of an event. + * If end date is not provided, progress bar animates indefinitely. + * + * @param id - A unique ID to distinguish instances. + * @param startDate - The start date of the tracked event. + * @param endDate - The end date of the tracked event. + */ +export const LinearAnimatedProgressBar = memo( + ({ + id, + startDate, + endDate, + }: { + id: string + startDate: Date + endDate: Date | null + }) => { + const height = 3 + const maskId = `mask-${id}` + const progressId = `progress-${id}` + const greenColor = 'rgb(74 222 128)' + const purpleColor = 'hsl(265deg 100% 75%)' + + let duration: string | number + + const isIndefinite = isNull(endDate) + + if (isIndefinite) { + duration = 'infinite' + return ( + + + + + + + + + + + + + + + + + + + ) + } else { + const { + totalTimeInSeconds, + totalTimeElapsedInSeconds, + totalTimeRemainingInSeconds, + isComplete, + } = getCountdownTimeStatus(startDate, endDate) + + const percentElapsed = Math.floor( + (totalTimeElapsedInSeconds / totalTimeInSeconds) * 100 + ) + + duration = isComplete ? 0.5 : totalTimeRemainingInSeconds + + return ( + + + + + + + + + + + + + + + + + + {isComplete && ( + + )} + + {isComplete && ( + + )} + + ) + } + } +) diff --git a/packages/widget/src/components/Maintenance/Maintenance.tsx b/packages/widget/src/components/Maintenance/Maintenance.tsx new file mode 100644 index 0000000000..b46ff35656 --- /dev/null +++ b/packages/widget/src/components/Maintenance/Maintenance.tsx @@ -0,0 +1,106 @@ +import { useBridgeState } from '@/state/slices/bridge/hooks' +import { isChainIncluded } from '@/utils/isChainIncluded' +import { useEventCountdownProgressBar } from '@/hooks/useEventCountdownProgressBar' +import { MaintenanceWarningMessage } from './MaintenanceWarningMessage' +import { getSynapsePauseData } from '@/utils/getSynapsePauseData' +import { isValidBridgeModule } from '@/utils/isValidBridgeModule' + +interface ChainPause { + id: string + pausedFromChains: number[] + pausedToChains: number[] + pauseBridge: boolean + startTimePauseChain: Date + endTimePauseChain: Date | null + inputWarningMessage: string + progressBarMessage: string + disableWarning: boolean + disableCountdown: boolean +} + +interface BridgeModulePause { + chainId: number | undefined + bridgeModuleName: 'SynapseBridge' | 'SynapseRFQ' | 'SynapseCCTP' | 'ALL' +} + +export const getMaintenanceData = () => { + const { pausedChainsData, pausedModulesData } = getSynapsePauseData() + + const pausedChainsList: ChainPause[] = pausedChainsData + ? pausedChainsData?.map((pause: ChainPause) => { + return { + ...pause, + startTimePauseChain: new Date(pause.startTimePauseChain), + endTimePauseChain: pause.endTimePauseChain + ? new Date(pause.endTimePauseChain) + : null, + inputWarningMessage: pause.inputWarningMessage, + progressBarMessage: pause.progressBarMessage, + } + }) + : [] + + const pausedModulesList: BridgeModulePause[] = pausedModulesData + ? pausedModulesData?.map((route: BridgeModulePause) => { + if (!isValidBridgeModule(route.bridgeModuleName)) { + throw new Error(`Invalid module type: ${route.bridgeModuleName}`) + } + + return { + ...route, + bridgeModuleName: route.bridgeModuleName as + | 'SynapseBridge' + | 'SynapseRFQ' + | 'SynapseCCTP' + | 'ALL', + } + }) + : [] + + return { + pausedChainsList, + pausedModulesList, + } +} + +export const useMaintenance = () => { + const { originChainId, destinationChainId } = useBridgeState() + const { pausedChainsList, pausedModulesList } = getMaintenanceData() + + const activePause = pausedChainsList.find( + (pauseData) => + isChainIncluded(pauseData?.pausedFromChains, [originChainId]) || + isChainIncluded(pauseData?.pausedToChains, [destinationChainId]) + ) + + const { isPending: isBridgePaused, EventCountdownProgressBar } = + useEventCountdownProgressBar( + activePause?.progressBarMessage, + activePause?.startTimePauseChain, + activePause?.endTimePauseChain, + activePause?.disableCountdown + ) + + const BridgeMaintenanceProgressBar = () => EventCountdownProgressBar + + const BridgeMaintenanceWarningMessage = () => ( + + ) + + return { + isBridgePaused, + pausedChainsList, + pausedModulesList, + BridgeMaintenanceProgressBar, + BridgeMaintenanceWarningMessage, + } +} diff --git a/packages/widget/src/components/Maintenance/MaintenanceWarningMessage.tsx b/packages/widget/src/components/Maintenance/MaintenanceWarningMessage.tsx new file mode 100644 index 0000000000..b21e9b0154 --- /dev/null +++ b/packages/widget/src/components/Maintenance/MaintenanceWarningMessage.tsx @@ -0,0 +1,55 @@ +import { getCountdownTimeStatus } from '@/utils/getCountdownTimeStatus' +import { isChainIncluded } from '@/utils/isChainIncluded' + +/** + * Displays warning message triggered by start and end time. + * Renders for selected origin and/or destination chain IDs. + */ +export const MaintenanceWarningMessage = ({ + originChainId, + destinationChainId, + startDate, + endDate, + pausedOriginChains, + pausedDestinationChains, + warningMessage, + disabled = false, +}: { + originChainId: number + destinationChainId: number + startDate: Date + endDate: Date + pausedOriginChains: number[] + pausedDestinationChains: number[] + warningMessage: any + disabled?: boolean +}) => { + const isWarningChain = + isChainIncluded([originChainId], pausedOriginChains) || + isChainIncluded([destinationChainId], pausedDestinationChains) + + const { isComplete } = getCountdownTimeStatus(startDate, endDate) + + if (isComplete || disabled) return null + + if (isWarningChain) { + return + } + + return null +} + +export const WarningMessage = ({ + header, + message, +}: { + header?: string + message?: React.ReactNode +}) => { + return ( + + {header && {header}} + {message && {message}} + + ) +} diff --git a/packages/widget/src/components/Transaction.tsx b/packages/widget/src/components/Transaction.tsx index 48db78b92c..052069d3c9 100644 --- a/packages/widget/src/components/Transaction.tsx +++ b/packages/widget/src/components/Transaction.tsx @@ -17,8 +17,8 @@ import { TimeRemaining } from '@/components/TimeRemaining' import { DropdownMenu } from '@/components/ui/DropdownMenu' import { MenuItem } from '@/components/ui/MenuItem' import { CHAINS_BY_ID } from '@/constants/chains' -import { TransactionSupport } from './TransactionSupport' -import { AnimatedProgressBar } from './AnimatedProgressBar' +import { TransactionSupport } from '@/components/TransactionSupport' +import { AnimatedProgressBar } from '@/components/AnimatedProgressBar' export const Transaction = ({ connectedAddress, diff --git a/packages/widget/src/components/Widget.tsx b/packages/widget/src/components/Widget.tsx index 2c06d7c37d..63783081ba 100644 --- a/packages/widget/src/components/Widget.tsx +++ b/packages/widget/src/components/Widget.tsx @@ -60,6 +60,7 @@ import { useSynapseContext } from '@/providers/SynapseProvider' import { getFromTokens } from '@/utils/routeMaker/getFromTokens' import { getSymbol } from '@/utils/routeMaker/generateRoutePossibilities' import { findTokenByRouteSymbol } from '@/utils/findTokenByRouteSymbol' +import { useMaintenance } from '@/components/Maintenance/Maintenance' interface WidgetProps { customTheme: CustomThemeVariables @@ -94,6 +95,12 @@ export const Widget = ({ destinationChainId, destinationToken, } = useBridgeState() + const { + isBridgePaused, + pausedModulesList, + BridgeMaintenanceProgressBar, + BridgeMaintenanceWarningMessage, + } = useMaintenance() const allTokens = useMemo(() => { return getFromTokens({ @@ -206,6 +213,7 @@ export const Widget = ({ debouncedInputAmount, synapseSDK, requestId: thisRequestId, + pausedModules: pausedModulesList, }) ) } @@ -385,6 +393,7 @@ export const Widget = ({ className={`grid gap-2 text-[--synapse-text] w-full ${containerStyle}`} style={{ background: 'var(--synapse-root)' }} > + + diff --git a/packages/widget/src/constants/index.ts b/packages/widget/src/constants/index.ts index 73bb92c1b9..83c606ce22 100644 --- a/packages/widget/src/constants/index.ts +++ b/packages/widget/src/constants/index.ts @@ -27,3 +27,8 @@ export const MAX_UINT256 = export const TRANSACTION_SUPPORT_URL = 'https://docs.synapseprotocol.com/synapse-bridge/synapse-bridge/transaction-support-faq' + +export const PAUSED_CHAINS_URL = + 'https://raw.githubusercontent.com/synapsecns/sanguine/master/packages/synapse-interface/public/pauses/v1/paused-chains.json' +export const PAUSED_MODULES_URL = + 'https://raw.githubusercontent.com/synapsecns/sanguine/master/packages/synapse-interface/public/pauses/v1/paused-bridge-modules.json' diff --git a/packages/widget/src/hooks/useEventCountdownProgressBar.tsx b/packages/widget/src/hooks/useEventCountdownProgressBar.tsx new file mode 100644 index 0000000000..5454559406 --- /dev/null +++ b/packages/widget/src/hooks/useEventCountdownProgressBar.tsx @@ -0,0 +1,56 @@ +import { useIntervalTimer } from '@/hooks/useIntervalTimer' +import { getCountdownTimeStatus } from '@/utils/getCountdownTimeStatus' +import { EventCountdownProgressBar } from '@/components/Maintenance/EventCountdownProgressBar' + +/** + * A hook that constructs a progress bar with a custom message and countdown timer. + * + * @param eventLabel - A description for the tracked event. + * @param startDate - The start date of the tracked event. + * @param endDate - The end date of the tracked event. + */ + +export const useEventCountdownProgressBar = ( + eventLabel: string, + startDate: Date, + endDate: Date | null, + hideProgress?: boolean +): { + isPending: boolean + isComplete: boolean + EventCountdownProgressBar: JSX.Element +} => { + let status: 'idle' | 'pending' | 'complete' + + const { totalTimeRemainingInMinutes, hoursRemaining, isComplete, isPending } = + getCountdownTimeStatus(startDate, endDate) + + useIntervalTimer(60000, isComplete || !startDate) + + const timeRemaining: string = + totalTimeRemainingInMinutes > 90 + ? `${hoursRemaining}h` + : `${totalTimeRemainingInMinutes}m` + + if (isComplete) { + status = 'complete' + } else if (isPending) { + status = 'pending' + } else { + status = 'idle' + } + + return { + isPending, + isComplete, + EventCountdownProgressBar: !hideProgress && ( + + ), + } +} diff --git a/packages/widget/src/hooks/useIntervalTimer.ts b/packages/widget/src/hooks/useIntervalTimer.ts new file mode 100644 index 0000000000..b99888e804 --- /dev/null +++ b/packages/widget/src/hooks/useIntervalTimer.ts @@ -0,0 +1,33 @@ +import { useState, useEffect } from 'react' + +import { getTimeMinutesFromNow } from '@/utils/getTimeMinutesFromNow' + +/** + * A hook for setting an interval based timer. + * + * @param intervalInMs - The duration between intervals, in ms. + * @param isDisabled - A boolean that determines if timer runs. + */ +export const useIntervalTimer = ( + intervalInMs: number, + isDisabled?: boolean +) => { + const [currentTime, setCurrentTime] = useState( + getTimeMinutesFromNow(0) + ) + + useEffect(() => { + if (!isDisabled) { + const interval = setInterval(() => { + const newCurrentTime = getTimeMinutesFromNow(0) + setCurrentTime(newCurrentTime) + }, intervalInMs) + + return () => { + clearInterval(interval) + } + } + }, [isDisabled]) + + return currentTime +} diff --git a/packages/widget/src/state/slices/bridgeQuote/hooks.ts b/packages/widget/src/state/slices/bridgeQuote/hooks.ts index 0a584ce67f..7e49f05e9d 100644 --- a/packages/widget/src/state/slices/bridgeQuote/hooks.ts +++ b/packages/widget/src/state/slices/bridgeQuote/hooks.ts @@ -8,6 +8,7 @@ import { stringToBigInt } from '@/utils/stringToBigInt' import { powBigInt } from '@/utils/powBigInt' import { formatBigIntToString } from '@/utils/formatBigIntToString' import { calculateExchangeRate } from '@/utils/calculateExchangeRate' +import { getBridgeModuleNames } from '@/utils/getBridgeModuleNames' export const useBridgeQuoteState = (): RootState['bridgeQuote'] => { return useAppSelector((state) => state.bridgeQuote) @@ -24,6 +25,7 @@ export const fetchBridgeQuote = createAsyncThunk( debouncedInputAmount, synapseSDK, requestId, + pausedModules, }: { originChainId: number destinationChainId: number @@ -33,6 +35,7 @@ export const fetchBridgeQuote = createAsyncThunk( debouncedInputAmount: string synapseSDK: any requestId: number + pausedModules: any }) => { const allQuotes = await synapseSDK.allBridgeQuotes( originChainId, @@ -42,7 +45,21 @@ export const fetchBridgeQuote = createAsyncThunk( amount ) - const rfqQuote = allQuotes.find((q) => q.bridgeModuleName === 'SynapseRFQ') + const pausedBridgeModules = new Set( + pausedModules + .filter((module) => + module.chainId ? module.chainId === originChainId : true + ) + .flatMap(getBridgeModuleNames) + ) + + const activeQuotes = allQuotes.filter( + (fetchedQuote) => !pausedBridgeModules.has(fetchedQuote.bridgeModuleName) + ) + + const rfqQuote = activeQuotes.find( + (q) => q.bridgeModuleName === 'SynapseRFQ' + ) let quote @@ -50,7 +67,7 @@ export const fetchBridgeQuote = createAsyncThunk( quote = rfqQuote } else { /* allBridgeQuotes returns sorted quotes by maxAmountOut descending */ - quote = allQuotes[0] + quote = activeQuotes[0] } const { diff --git a/packages/widget/src/utils/actions/fetchTokenBalances.ts b/packages/widget/src/utils/actions/fetchTokenBalances.ts index a1cbcbd64c..80eaba5b29 100644 --- a/packages/widget/src/utils/actions/fetchTokenBalances.ts +++ b/packages/widget/src/utils/actions/fetchTokenBalances.ts @@ -1,7 +1,7 @@ import { Contract, ethers, AbiCoder, ZeroAddress } from 'ethers' import { BridgeableToken } from 'types' -import { formatBigIntToString } from '../formatBigIntToString' +import { formatBigIntToString } from '@/utils/formatBigIntToString' import multicallAbi from '../../constants/abis/multicall.json' import erc20Abi from '../../constants/abis/erc20.json' diff --git a/packages/widget/src/utils/fetchJsonData.ts b/packages/widget/src/utils/fetchJsonData.ts new file mode 100644 index 0000000000..ec8c05ea86 --- /dev/null +++ b/packages/widget/src/utils/fetchJsonData.ts @@ -0,0 +1,7 @@ +export const fetchJSONData = async (url: string): Promise => { + const response = await fetch(url) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + return response.json() +} diff --git a/packages/widget/src/utils/getBridgeModuleNames.ts b/packages/widget/src/utils/getBridgeModuleNames.ts new file mode 100644 index 0000000000..a378b38138 --- /dev/null +++ b/packages/widget/src/utils/getBridgeModuleNames.ts @@ -0,0 +1,6 @@ +export const getBridgeModuleNames = (module) => { + if (module.bridgeModuleName === 'ALL') { + return ['SynapseRFQ', 'SynapseCCTP', 'SynapseBridge'] + } + return [module.bridgeModuleName] +} diff --git a/packages/widget/src/utils/getCountdownTimeStatus.ts b/packages/widget/src/utils/getCountdownTimeStatus.ts new file mode 100644 index 0000000000..cd0d8e7ed4 --- /dev/null +++ b/packages/widget/src/utils/getCountdownTimeStatus.ts @@ -0,0 +1,109 @@ +import { isNull } from 'lodash' + +export const getCountdownTimeStatus = ( + startDate: Date | null, + endDate: Date | null +) => { + if (!startDate && !endDate) { + return { + currentDate: null, + currentTimeInSeconds: null, + startTimeInSeconds: null, + endTimeInSeconds: null, + totalTimeInSeconds: null, + totalTimeElapsedInSeconds: null, + totalTimeRemainingInSeconds: null, + totalTimeRemainingInMinutes: null, + daysRemaining: null, + hoursRemaining: null, + minutesRemaining: null, + secondsRemaining: null, + isStarted: false, + isComplete: false, + isPending: false, + } + } + + const currentDate = new Date() + const currentTimeInSeconds = Math.floor(currentDate.getTime() / 1000) + const startTimeInSeconds = Math.floor(startDate.getTime() / 1000) + + const isStarted = currentTimeInSeconds >= startTimeInSeconds + const isIndefinite = isNull(endDate) + + if (isIndefinite) { + return { + currentDate, + currentTimeInSeconds, + startTimeInSeconds, + endTimeInSeconds: null, + totalTimeInSeconds: null, + totalTimeElapsedInSeconds: null, + totalTimeRemainingInSeconds: null, + totalTimeRemainingInMinutes: null, + daysRemaining: null, + hoursRemaining: null, + minutesRemaining: null, + secondsRemaining: null, + isStarted, + isComplete: false, + isPending: isStarted, + } + } + + const { daysRemaining, hoursRemaining, minutesRemaining, secondsRemaining } = + calculateTimeUntilTarget(endDate) + + const endTimeInSeconds = Math.floor(endDate.getTime() / 1000) + const totalTimeInSeconds = endTimeInSeconds - startTimeInSeconds + + const totalTimeElapsedInSeconds = currentTimeInSeconds - startTimeInSeconds + const totalTimeRemainingInSeconds = endTimeInSeconds - currentTimeInSeconds + const totalTimeRemainingInMinutes = Math.ceil( + totalTimeRemainingInSeconds / 60 + ) + + const isComplete = totalTimeRemainingInSeconds <= 0 + const isPending = isStarted && !isComplete + + return { + currentDate, + currentTimeInSeconds, + startTimeInSeconds, + endTimeInSeconds, + totalTimeInSeconds, + totalTimeElapsedInSeconds, + totalTimeRemainingInSeconds, + totalTimeRemainingInMinutes, + daysRemaining, + hoursRemaining, + minutesRemaining, + secondsRemaining, + isStarted, + isComplete, + isPending, + } +} + +const calculateTimeUntilTarget = (targetDate: Date) => { + const currentDate = new Date() + const timeDifference = targetDate.getTime() - currentDate.getTime() + const isComplete = timeDifference <= 0 + + const daysRemaining = Math.floor(timeDifference / (1000 * 60 * 60 * 24)) + const hoursRemaining = Math.ceil( + (timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) + ) + const minutesRemaining = Math.floor( + (timeDifference % (1000 * 60 * 60)) / (1000 * 60) + ) + const secondsRemaining = Math.floor((timeDifference % (1000 * 60)) / 1000) + + return { + daysRemaining, + hoursRemaining, + minutesRemaining, + secondsRemaining, + isComplete, + } +} diff --git a/packages/widget/src/utils/getSynapsePauseData.ts b/packages/widget/src/utils/getSynapsePauseData.ts new file mode 100644 index 0000000000..5d8f75edc4 --- /dev/null +++ b/packages/widget/src/utils/getSynapsePauseData.ts @@ -0,0 +1,57 @@ +import { PAUSED_CHAINS_URL, PAUSED_MODULES_URL } from '@/constants/index' +import { fetchJSONData } from '@/utils/fetchJsonData' + +enum SessionStorageKey { + CHAIN_PAUSE = 'synapse-paused-chains', + MODULE_PAUSE = 'synapse-paused-modules', +} + +let isFetching = false + +export const getSynapsePauseData = () => { + const fetchAndStoreData = async () => { + if (isFetching) { + return + } + try { + isFetching = true + const chainsData = await fetchJSONData(PAUSED_CHAINS_URL) + const modulesData = await fetchJSONData(PAUSED_MODULES_URL) + + sessionStorage.setItem( + SessionStorageKey.CHAIN_PAUSE, + JSON.stringify(chainsData) + ) + sessionStorage.setItem( + SessionStorageKey.MODULE_PAUSE, + JSON.stringify(modulesData) + ) + } catch (error) { + console.error( + '[Synapse Widget] Failed to fetch paused chains/modules: ', + error + ) + } finally { + setTimeout(() => { + isFetching = false + }, 1000) + } + } + + const readData = () => { + if (sessionStorage) { + const pausedChainsData = JSON.parse( + sessionStorage.getItem(SessionStorageKey.CHAIN_PAUSE) + ) + const pausedModulesData = JSON.parse( + sessionStorage.getItem(SessionStorageKey.MODULE_PAUSE) + ) + return { pausedChainsData, pausedModulesData } + } + return { pausedChainsData: null, pausedModulesData: null } + } + + fetchAndStoreData() + + return readData() +} diff --git a/packages/widget/src/utils/isChainIncluded.ts b/packages/widget/src/utils/isChainIncluded.ts new file mode 100644 index 0000000000..aa942d6d5f --- /dev/null +++ b/packages/widget/src/utils/isChainIncluded.ts @@ -0,0 +1,11 @@ +/** + * Checks if any of the chain IDs in `hasChains` are found within the `chainList` array. + * + * @param {number[]} chainList - The array of chain IDs to check against. + * @param {number[]} hasChains - The array of chain IDs to find within `chainList`. + * @returns {boolean} - True if any chain ID from `hasChains` is found in `chainList`, otherwise false. + */ + +export const isChainIncluded = (chainList: number[], hasChains: number[]) => { + return hasChains?.some((chainId) => chainList.includes(chainId)) +} diff --git a/packages/widget/src/utils/isValidBridgeModule.ts b/packages/widget/src/utils/isValidBridgeModule.ts new file mode 100644 index 0000000000..02223c974c --- /dev/null +++ b/packages/widget/src/utils/isValidBridgeModule.ts @@ -0,0 +1,5 @@ +export const isValidBridgeModule = ( + module: any +): module is 'SynapseBridge' | 'SynapseRFQ' | 'SynapseCCTP' | 'ALL' => { + return ['SynapseBridge', 'SynapseRFQ', 'SynapseCCTP', 'ALL'].includes(module) +} diff --git a/packages/widget/src/utils/routeMaker/generateRoutePossibilities.ts b/packages/widget/src/utils/routeMaker/generateRoutePossibilities.ts index c53d7de1de..2831c43374 100644 --- a/packages/widget/src/utils/routeMaker/generateRoutePossibilities.ts +++ b/packages/widget/src/utils/routeMaker/generateRoutePossibilities.ts @@ -1,12 +1,12 @@ import _ from 'lodash' import { BridgeableToken } from 'types' -import { flattenPausedTokens } from '../flattenPausedTokens' -import { getToChainIds } from './getToChainIds' -import { getFromChainIds } from './getFromChainIds' -import { getFromTokens } from './getFromTokens' -import { getToTokens } from './getToTokens' -import { findTokenByRouteSymbol } from '../findTokenByRouteSymbol' +import { flattenPausedTokens } from '@/utils/flattenPausedTokens' +import { getToChainIds } from '@/utils/routeMaker/getToChainIds' +import { getFromChainIds } from '@/utils/routeMaker/getFromChainIds' +import { getFromTokens } from '@/utils/routeMaker/getFromTokens' +import { getToTokens } from '@/utils/routeMaker/getToTokens' +import { findTokenByRouteSymbol } from '@/utils/findTokenByRouteSymbol' export const PAUSED_TO_CHAIN_IDS = [2000]