Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/synapse-interface/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [0.44.3](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.44.2...@synapsecns/synapse-interface@0.44.3) (2026-05-06)


### Bug Fixes

* **synapse-interface:** bridge pauses ([#4049](https://github.com/synapsecns/sanguine/issues/4049)) ([1205938](https://github.com/synapsecns/sanguine/commit/120593869020d9973483ba4ca03433b7ef4c8d70))





## [0.44.2](https://github.com/synapsecns/sanguine/compare/@synapsecns/synapse-interface@0.44.1...@synapsecns/synapse-interface@0.44.2) (2026-05-05)


Expand Down
13 changes: 9 additions & 4 deletions packages/synapse-interface/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,19 @@ The interface renders maintenance UI from shared pause artifacts:
2. Countdown Progress Bar at the top of Bridge / Swap cards.
3. Warning Message below the input UI in Bridge / Swap cards.

The widget still depends on these same pause artifact files and repository paths for its maintenance state, even though it fetches them through different remote URLs. Keep both files present at their current paths even when they are empty, because the widget is coupled to those artifact locations.
The widget still depends on these same pause artifact files and repository paths for its maintenance state, even though it fetches them through different remote URLs. Keep shared artifact files present at their current paths even when they are empty, because consumers may be coupled to those artifact locations.

The shared artifacts are:

- [Pause Chains JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-chains.json)
- [Pause Bridge Modules JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-bridge-modules.json)
- [Pause Bridge Modules To Chain JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-bridge-modules-to-chain.json)

Current repository state:

- `paused-chains.json` is intentionally shipped as an empty array. This repository no longer maintains chain-specific pause records in the shared artifacts.
- `paused-bridge-modules.json` remains the maintained pause artifact for bridge module filtering. Records must stay chain-scoped; do not add a global `ALL` pause record.
- `paused-bridge-modules.json` remains the maintained pause artifact for origin chain bridge module filtering. Records must stay chain-scoped with `chainId`; do not add a global `ALL` pause record.
- `paused-bridge-modules-to-chain.json` remains the maintained pause artifact for destination chain bridge module filtering. Records must stay chain-scoped with `toChainId`; do not add a global `ALL` pause record.
- Example files under `public/pauses/v1/examples/` are intentionally empty arrays so they do not advertise removed chain-specific or global configs.

When a shared pause artifact changes, the production webapp picks it up after:
Expand All @@ -91,7 +93,7 @@ This deployment flow applies to the interface only. After Step 1, the [Github Pa

## Bridge Module Pause

Use `paused-bridge-modules.json` to pause a specific bridge module on a specific chain. Supported bridge modules are:
Use `paused-bridge-modules.json` to pause a specific bridge module from a specific chain. Use `paused-bridge-modules-to-chain.json` to pause a specific bridge module to a specific chain. Supported bridge modules are:

- `SynapseRFQ`
- `SynapseCCTP`
Expand All @@ -100,7 +102,10 @@ Use `paused-bridge-modules.json` to pause a specific bridge module on a specific
### Bridge Module Pause Props

`chainId`
Chain ID of the chain where the bridge module should be paused.
Origin chain ID where the bridge module should be paused. Use only in `paused-bridge-modules.json`.

`toChainId`
Destination chain ID where the bridge module should be paused. Use only in `paused-bridge-modules-to-chain.json`.

`bridgeModuleName`
Accepts `SynapseRFQ`, `SynapseBridge`, or `SynapseCCTP`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ interface ChainPause {
}

export interface BridgeModulePause {
chainId?: number // If undefined, pause bridge module for all chains.
chainId?: number // Origin chain ID. If undefined, match any origin chain.
toChainId?: number // Destination chain ID. If undefined, match any destination chain.
bridgeModuleName: 'SynapseBridge' | 'SynapseRFQ' | 'SynapseCCTP' | 'ALL'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import {
import { fetchJsonData } from '../functions/fetchJsonData'
import pausedChains from '@/public/pauses/v1/paused-chains.json'
import pausedBridgeModules from '@/public/pauses/v1/paused-bridge-modules.json'
import pausedBridgeModulesToChain from '@/public/pauses/v1/paused-bridge-modules-to-chain.json'

const PAUSED_CHAINS_URL =
'https://synapsecns.github.io/sanguine/packages/synapse-interface/public/pauses/v1/paused-chains.json'
const PAUSED_MODULES_URL =
'https://synapsecns.github.io/sanguine/packages/synapse-interface/public/pauses/v1/paused-bridge-modules.json'
const PAUSED_MODULES_TO_CHAIN_URL =
'https://synapsecns.github.io/sanguine/packages/synapse-interface/public/pauses/v1/paused-bridge-modules-to-chain.json'

export const useSynapsePauseData = () => {
const dispatch = useAppDispatch()
Expand All @@ -25,9 +28,17 @@ export const useSynapsePauseData = () => {
try {
const pausedChainsData = await fetchJsonData(PAUSED_CHAINS_URL)
const pausedModulesData = await fetchJsonData(PAUSED_MODULES_URL)
const pausedModulesToChainData = await fetchJsonData(
PAUSED_MODULES_TO_CHAIN_URL
)

dispatch(setPausedChainsData(pausedChainsData))
dispatch(setPausedModulesData(pausedModulesData))
dispatch(
setPausedModulesData([
...pausedModulesData,
...pausedModulesToChainData,
])
)
} catch (error) {
console.error(
'Using local source, failed to fetch paused chains/modules: ',
Expand All @@ -36,7 +47,12 @@ export const useSynapsePauseData = () => {

/** Read local source if fetch fails as backup */
dispatch(setPausedChainsData(pausedChains))
dispatch(setPausedModulesData(pausedBridgeModules))
dispatch(
setPausedModulesData([
...pausedBridgeModules,
...pausedBridgeModulesToChain,
])
)
} finally {
setTimeout(() => {
setIsFetching(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useMemo } from 'react'
import { useTranslations } from 'next-intl'

import type { BridgeModulePause } from '@/components/Maintenance/Maintenance'
import { WarningMessage } from '@/components/Warning'
import { getPausedBridgeModuleNamesForRoute } from '@/utils/getPausedBridgeModuleNamesForRoute'

export const BridgeModulePausedWarning = ({
fromChainId,
toChainId,
pausedModulesList,
}: {
fromChainId: number
toChainId: number
pausedModulesList: BridgeModulePause[]
}) => {
const t = useTranslations('Bridge')
const pausedModuleNames = useMemo(
() =>
getPausedBridgeModuleNamesForRoute({
pausedModules: pausedModulesList,
fromChainId,
toChainId,
}),
[fromChainId, toChainId, pausedModulesList]
)

if (!fromChainId || !toChainId || pausedModuleNames.length === 0) {
return null
}

return (
<WarningMessage
twClassName="mb-2 border border-amber-500/30 !bg-amber-50 !text-amber-950 dark:!bg-amber-950/30 dark:!text-amber-100"
message={t('BridgeModulePauseWarningMessage')}
/>
)
}
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "الجسر",
"Send your assets across chains": "أرسل أصولك عبر السلاسل.",
"Bridge paused": "الجسر متوقف مؤقتًا",
"BridgeModulePauseWarningMessage": "الجسر متوقف مؤقتًا لهذا المسار. قد تكون عروض الأسعار أقل ملاءمة.",
"Please select Origin Network": "يرجى اختيار شبكة المصدر",
"Please select Destination network": "يرجى اختيار شبكة الوجهة",
"Please select an Origin token": "يرجى اختيار رمز المصدر",
Expand Down
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "Bridge",
"Send your assets across chains": "Send your assets across chains.",
"Bridge paused": "Bridge paused",
"BridgeModulePauseWarningMessage": "Bridge is paused for this route. Quotes may be less favorable.",
"Please select Origin Network": "Please select Origin Network",
"Please select Destination network": "Please select Destination network",
"Please select an Origin token": "Please select an Origin token",
Expand Down
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "Puente",
"Send your assets across chains": "Envía tus activos entre cadenas.",
"Bridge paused": "Puente en pausa",
"BridgeModulePauseWarningMessage": "El puente está en pausa para esta ruta. Las cotizaciones pueden ser menos favorables.",
"Please select Origin Network": "Por favor, selecciona la Red de Origen",
"Please select Destination network": "Por favor, selecciona la red de Destino",
"Please select an Origin token": "Por favor, selecciona un token de Origen",
Expand Down
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "Bridge",
"Send your assets across chains": "Envoyez vos actifs à travers les chaînes.",
"Bridge paused": "Bridge en pause",
"BridgeModulePauseWarningMessage": "Le bridge est en pause pour cette route. Les offres peuvent être moins favorables.",
"Please select Origin Network": "Veuillez sélectionner le réseau d'origine",
"Please select Destination network": "Veuillez sélectionner le réseau de destination",
"Please select an Origin token": "Veuillez sélectionner un jeton d'origine",
Expand Down
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "ブリッジ",
"Send your assets across chains": "チェーン間でアセットを送信します。",
"Bridge paused": "ブリッジ一時停止中",
"BridgeModulePauseWarningMessage": "このルートではブリッジが一時停止中です。見積もりが不利になる場合があります。",
"Please select Origin Network": "オリジンネットワークを選択してください",
"Please select Destination network": "宛先ネットワークを選択してください",
"Please select an Origin token": "オリジントークンを選択してください",
Expand Down
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "Köprü",
"Send your assets across chains": "Varlıklarınızı zincirler arasında gönderin.",
"Bridge paused": "Köprü duraklatıldı",
"BridgeModulePauseWarningMessage": "Köprü bu rota için duraklatıldı. Teklifler daha az avantajlı olabilir.",
"Please select Origin Network": "Lütfen Kaynak Ağı seçin",
"Please select Destination network": "Lütfen Hedef ağı seçin",
"Please select an Origin token": "Lütfen bir Kaynak token seçin",
Expand Down
1 change: 1 addition & 0 deletions packages/synapse-interface/messages/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Bridge": "桥接",
"Send your assets across chains": "跨链发送您的资产。",
"Bridge paused": "桥接已暂停",
"BridgeModulePauseWarningMessage": "此路线的桥接已暂停。报价可能不够优惠。",
"Please select Origin Network": "请选择来源网络",
"Please select Destination network": "请选择目标网络",
"Please select an Origin token": "请选择来源代币",
Expand Down
2 changes: 1 addition & 1 deletion packages/synapse-interface/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@synapsecns/synapse-interface",
"version": "0.44.2",
"version": "0.44.3",
"private": true,
"engines": {
"node": ">=18"
Expand Down
25 changes: 23 additions & 2 deletions packages/synapse-interface/pages/state-managed-bridge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import toast from 'react-hot-toast'
import { useEffect, useRef, useState } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { Address, zeroAddress, isAddress } from 'viem'
import { polygon } from 'viem/chains'
import { useAccount } from 'wagmi'
Expand All @@ -17,6 +17,7 @@ import { InputContainer } from '@/components/StateManagedBridge/InputContainer'
import { OutputContainer } from '@/components/StateManagedBridge/OutputContainer'
import { BridgeExchangeRateInfo } from '@/components/StateManagedBridge/BridgeExchangeRateInfo'
import { BridgeTransactionButton } from '@/components/StateManagedBridge/BridgeTransactionButton'
import { BridgeModulePausedWarning } from '@/components/StateManagedBridge/BridgeModulePausedWarning'
import ExplorerToastLink from '@/components/ExplorerToastLink'
import { SwitchButton } from '@/components/buttons/SwitchButton'
import { PageHeader } from '@/components/PageHeader'
Expand Down Expand Up @@ -126,6 +127,10 @@ const StateManagedBridge = () => {
BridgeMaintenanceProgressBar,
BridgeMaintenanceWarningMessage,
} = useMaintenance()
const pausedModulesKey = useMemo(
() => JSON.stringify(pausedModulesList),
[pausedModulesList]
)

useEffect(() => {
segmentAnalyticsEvent(
Expand All @@ -151,7 +156,16 @@ const StateManagedBridge = () => {
} else {
dispatch(resetBridgeQuote())
}
}, [fromChainId, toChainId, fromToken, toToken, debouncedFromValue, address, destinationAddress])
}, [
fromChainId,
toChainId,
fromToken,
toToken,
debouncedFromValue,
address,
destinationAddress,
pausedModulesKey,
])

const getAndSetBridgeQuote = async () => {
currentSDKRequestID.current += 1
Expand Down Expand Up @@ -507,6 +521,13 @@ const StateManagedBridge = () => {
{!(
fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id
) && <BridgeExchangeRateInfo />}
<BridgeModulePausedWarning
fromChainId={fromChainId}
toChainId={
toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId
}
pausedModulesList={pausedModulesList}
/>
{toChainId === HYPERLIQUID.id && (
<HyperliquidDepositInfo
fromChainId={fromChainId}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[
{
"toChainId": 1,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 25,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 250,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 288,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 1284,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 1285,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 2000,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 7700,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 53935,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 81457,
"bridgeModuleName": "SynapseBridge"
},
{
"toChainId": 1313161554,
"bridgeModuleName": "SynapseBridge"
}
]
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
[]
[
{
"chainId": 288,
"bridgeModuleName": "SynapseBridge"
},
{
"chainId": 2000,
"bridgeModuleName": "SynapseBridge"
},
{
"chainId": 53935,
"bridgeModuleName": "SynapseBridge"
}
]
12 changes: 6 additions & 6 deletions packages/synapse-interface/slices/bridgeQuote/thunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AcceptedChainId, CHAINS_BY_ID } from '@/constants/chains'
import { segmentAnalyticsEvent } from '@/contexts/SegmentAnalyticsProvider'
import { stringToBigInt, formatBigIntToString } from '@/utils/bigint/format'
import { calculateExchangeRate } from '@/utils/calculateExchangeRate'
import { getBridgeModuleNames } from '@/utils/getBridgeModuleNames'
import { getPausedBridgeModuleNamesForRoute } from '@/utils/getPausedBridgeModuleNamesForRoute'
import { Token } from '@/utils/types'
import { BridgeModulePause } from '@/components/Maintenance/Maintenance'
import { HYPERLIQUID } from '@/constants/chains/master'
Expand Down Expand Up @@ -62,11 +62,11 @@ export const fetchBridgeQuote = createAsyncThunk(
})

const pausedBridgeModules = new Set(
pausedModulesList
.filter((module) =>
module.chainId ? module.chainId === fromChainId : true
)
.flatMap(getBridgeModuleNames)
getPausedBridgeModuleNamesForRoute({
pausedModules: pausedModulesList,
fromChainId,
toChainId,
})
)
const activeQuotes = allQuotes.filter(
(quote) => !quote.moduleNames.some((m) => pausedBridgeModules.has(m))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getBridgeModuleNames } from '@/utils/getBridgeModuleNames'

type BridgeModulePauseLike = {
chainId?: number
toChainId?: number
bridgeModuleName: string
}

export const getPausedBridgeModuleNamesForRoute = ({
pausedModules,
fromChainId,
toChainId,
}: {
pausedModules: BridgeModulePauseLike[]
fromChainId: number
toChainId: number
}) => {
return Array.from(
new Set(
pausedModules
.filter(
(module) =>
(module.chainId ? module.chainId === fromChainId : true) &&
(module.toChainId ? module.toChainId === toChainId : true)
)
.flatMap(getBridgeModuleNames)
)
).sort((a, b) => a.localeCompare(b))
}
Loading
Loading