diff --git a/cspell.json b/cspell.json
index 059350f412..af1ce1eda0 100644
--- a/cspell.json
+++ b/cspell.json
@@ -37,11 +37,13 @@
"ethersproject",
"ethtx",
"extralight",
+ "fastbridge",
"ftmscan",
"getids",
"gitbook",
"gorm",
"headlessui",
+ "hyperliquid",
"incentivized",
"interchain",
"ipfs",
diff --git a/docs/bridge/blog-posts/2024-12-12-fastbridgev2-post.md b/docs/bridge/blog-posts/2024-12-12-fastbridgev2-post.md
index c91263f22a..3e87bf8d69 100644
--- a/docs/bridge/blog-posts/2024-12-12-fastbridgev2-post.md
+++ b/docs/bridge/blog-posts/2024-12-12-fastbridgev2-post.md
@@ -87,7 +87,7 @@ The real-time nature of WebSockets dramatically reduces quote latency. Rather th
:::info
-The Synapse Intent Network is backwards combatible with the original Fastbridge Contracts.
+The Synapse Intent Network is backwards compatible with the original Fastbridge Contracts.
:::
diff --git a/packages/synapse-interface/assets/chains/hyperliquid.svg b/packages/synapse-interface/assets/chains/hyperliquid.svg
new file mode 100644
index 0000000000..c9eb0bd097
--- /dev/null
+++ b/packages/synapse-interface/assets/chains/hyperliquid.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/synapse-interface/components/HyperliquidDepositInfo.tsx b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx
new file mode 100644
index 0000000000..6d04bd8e1d
--- /dev/null
+++ b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx
@@ -0,0 +1,181 @@
+import { ARBITRUM } from '@/constants/chains/master'
+
+export const HyperliquidDepositInfo = ({
+ fromChainId,
+ isOnArbitrum,
+ hasDepositedOnHyperliquid,
+}) => {
+ if (fromChainId !== ARBITRUM.id) {
+ return (
+
+
+
+
+
Step 2
+
+
+
Deposit (Hyperliquid)
+
+
+
+
+ )
+ }
+
+ if (hasDepositedOnHyperliquid) {
+ return (
+
+
+
+
+
Step 2
+
+
+
Deposit (Hyperliquid)
+
+
+
+
+ )
+ }
+
+ if (fromChainId === ARBITRUM.id && isOnArbitrum) {
+ return (
+
+
+
+
+
Step 2
+
+
+
Deposit (Hyperliquid)
+
+
+
+
+ )
+ }
+}
+
+const CompletedCheckMarkCircle = () => {
+ return (
+
+ )
+}
+
+const GreenStep1Circle = () => {
+ return (
+
+ )
+}
+
+const GreenStep2Circle = () => {
+ return (
+
+ )
+}
+
+const GrayStep2Circle = () => {
+ return (
+
+ )
+}
diff --git a/packages/synapse-interface/components/StateManagedBridge/BridgeQuoteResetTimer.tsx b/packages/synapse-interface/components/StateManagedBridge/BridgeQuoteResetTimer.tsx
index 86717650ba..4c511d5951 100644
--- a/packages/synapse-interface/components/StateManagedBridge/BridgeQuoteResetTimer.tsx
+++ b/packages/synapse-interface/components/StateManagedBridge/BridgeQuoteResetTimer.tsx
@@ -42,7 +42,7 @@ const AnimatedLoadingCircle = () => {
fill="none"
className="absolute block -rotate-90"
>
-
+
-
+
HYPERLIQUID_MINIMUM_DEPOSIT
+ ? true
+ : false
+ : true
+
const {
hasValidInput,
hasValidQuote,
@@ -78,7 +87,8 @@ export const BridgeTransactionButton = ({
(isConnected && !hasValidQuote) ||
(isConnected && !hasSufficientBalance) ||
(isConnected && isQuoteStale) ||
- (destinationAddress && !isAddress(destinationAddress))
+ (destinationAddress && !isAddress(destinationAddress)) ||
+ !hasHyperliquidMinDeposit
let buttonProperties
@@ -138,6 +148,11 @@ export const BridgeTransactionButton = ({
label: t('Amount must be greater than fee'),
onClick: null,
}
+ } else if (!hasHyperliquidMinDeposit) {
+ buttonProperties = {
+ label: `${HYPERLIQUID_MINIMUM_DEPOSIT} USDC Minimum`,
+ onClick: null,
+ }
} else if (
bridgeQuote.bridgeModuleName !== null &&
!isLoading &&
diff --git a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx
new file mode 100644
index 0000000000..f089a15ca2
--- /dev/null
+++ b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx
@@ -0,0 +1,187 @@
+import { useEffect, useState } from 'react'
+import { useAccount, useAccountEffect, useSwitchChain } from 'wagmi'
+import { useConnectModal } from '@rainbow-me/rainbowkit'
+import { useTranslations } from 'next-intl'
+import { erc20Abi } from 'viem'
+import {
+ simulateContract,
+ waitForTransactionReceipt,
+ writeContract,
+} from '@wagmi/core'
+
+import { wagmiConfig } from '@/wagmiConfig'
+import { useAppDispatch } from '@/store/hooks'
+import { useWalletState } from '@/slices/wallet/hooks'
+import { useBridgeState } from '@/slices/bridge/hooks'
+import { TransactionButton } from '@/components/buttons/TransactionButton'
+import { useBridgeValidations } from './hooks/useBridgeValidations'
+import { USDC } from '@/constants/tokens/bridgeable'
+import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master'
+import { stringToBigInt } from '@/utils/bigint/format'
+import { fetchAndStoreSingleNetworkPortfolioBalances } from '@/slices/portfolio/hooks'
+import { segmentAnalyticsEvent } from '@/contexts/SegmentAnalyticsProvider'
+import { addPendingBridgeTransaction } from '@/slices/transactions/actions'
+import { getUnixTimeMinutesFromNow } from '@/utils/time'
+import { HYPERLIQUID_MINIMUM_DEPOSIT } from '@/constants'
+
+const HYPERLIQUID_DEPOSIT_ADDRESS = '0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7'
+
+const deposit = async (amount: bigint) => {
+ try {
+ const { request } = await simulateContract(wagmiConfig, {
+ chainId: ARBITRUM.id,
+ address: USDC.addresses[ARBITRUM.id],
+ abi: erc20Abi,
+ functionName: 'transfer',
+ args: [HYPERLIQUID_DEPOSIT_ADDRESS, amount],
+ })
+
+ const hash = await writeContract(wagmiConfig, request)
+
+ const txReceipt = await waitForTransactionReceipt(wagmiConfig, { hash })
+
+ return txReceipt
+ } catch (error) {
+ console.error('Confirmation error:', error)
+ throw error
+ }
+}
+
+export const HyperliquidTransactionButton = ({
+ isTyping,
+ hasDepositedOnHyperliquid,
+ setHasDepositedOnHyperliquid,
+}) => {
+ const [isDepositing, setIsDepositing] = useState(false)
+
+ const { address } = useAccount()
+
+ const dispatch = useAppDispatch()
+ const { openConnectModal } = useConnectModal()
+ const [isConnected, setIsConnected] = useState(false)
+
+ const { isConnected: isConnectedInit } = useAccount()
+ const { chains, switchChain } = useSwitchChain()
+
+ const { fromToken, fromChainId, debouncedFromValue } = useBridgeState()
+
+ const { isWalletPending } = useWalletState()
+
+ const { hasValidInput, hasSufficientBalance, onSelectedChain } =
+ useBridgeValidations()
+
+ const depositingMinimumAmount =
+ Number(debouncedFromValue) >= HYPERLIQUID_MINIMUM_DEPOSIT
+
+ const t = useTranslations('Bridge')
+
+ const amount = stringToBigInt(
+ debouncedFromValue,
+ fromToken?.decimals[fromChainId]
+ )
+
+ const handleDeposit = async () => {
+ setIsDepositing(true)
+ const currentTimestamp: number = getUnixTimeMinutesFromNow(0)
+ try {
+ const txReceipt = await deposit(amount)
+
+ setHasDepositedOnHyperliquid(true)
+ segmentAnalyticsEvent(`[Hyperliquid Deposit]`, {
+ inputAmount: debouncedFromValue,
+ })
+ dispatch(
+ fetchAndStoreSingleNetworkPortfolioBalances({
+ address,
+ chainId: ARBITRUM.id,
+ })
+ )
+ dispatch(
+ addPendingBridgeTransaction({
+ id: currentTimestamp,
+ originChain: ARBITRUM,
+ originToken: fromToken,
+ originValue: debouncedFromValue,
+ destinationChain: HYPERLIQUID,
+ destinationToken: undefined,
+ transactionHash: txReceipt.transactionHash,
+ timestamp: undefined,
+ isSubmitted: false,
+ estimatedTime: undefined,
+ bridgeModuleName: undefined,
+ destinationAddress: undefined,
+ routerAddress: undefined,
+ })
+ )
+ } catch (error) {
+ console.error('Deposit error:', error)
+ } finally {
+ setIsDepositing(false)
+ }
+ }
+
+ useAccountEffect({
+ onDisconnect() {
+ setIsConnected(false)
+ },
+ })
+
+ useEffect(() => {
+ setIsConnected(isConnectedInit)
+ }, [isConnectedInit])
+
+ const isButtonDisabled =
+ isTyping ||
+ isDepositing ||
+ !depositingMinimumAmount ||
+ isWalletPending ||
+ !hasValidInput ||
+ (isConnected && !hasSufficientBalance)
+
+ let buttonProperties
+
+ if (isConnected && !hasSufficientBalance) {
+ buttonProperties = {
+ label: t('Insufficient balance'),
+ onClick: null,
+ }
+ } else if (!depositingMinimumAmount) {
+ buttonProperties = {
+ label: `${HYPERLIQUID_MINIMUM_DEPOSIT} USDC Minimum`,
+ onClick: null,
+ }
+ } else if (!isConnected && hasValidInput) {
+ buttonProperties = {
+ label: t('Connect Wallet to Bridge'),
+ onClick: openConnectModal,
+ }
+ } else if (!onSelectedChain && hasValidInput) {
+ buttonProperties = {
+ label: t('Switch to {chainName}', {
+ chainName: chains.find((c) => c.id === fromChainId)?.name,
+ }),
+ onClick: () => switchChain({ chainId: fromChainId }),
+ pendingLabel: t('Switching chains'),
+ }
+ } else {
+ buttonProperties = {
+ onClick: handleDeposit,
+ label: t('Deposit {symbol}', { symbol: fromToken?.symbol }),
+ pendingLabel: t('Depositing'),
+ }
+ }
+
+ return (
+ buttonProperties && (
+ <>
+
+
+
+ >
+ )
+ )
+}
diff --git a/packages/synapse-interface/components/StateManagedBridge/OutputContainer.tsx b/packages/synapse-interface/components/StateManagedBridge/OutputContainer.tsx
index 5af733cb91..6fed2c1b97 100644
--- a/packages/synapse-interface/components/StateManagedBridge/OutputContainer.tsx
+++ b/packages/synapse-interface/components/StateManagedBridge/OutputContainer.tsx
@@ -16,6 +16,7 @@ import { useWalletState } from '@/slices/wallet/hooks'
import { useBridgeQuoteState } from '@/slices/bridgeQuote/hooks'
import { useBridgeValidations } from './hooks/useBridgeValidations'
import { useTranslations } from 'next-intl'
+import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master'
interface OutputContainerProps {
isQuoteStale: boolean
@@ -26,6 +27,7 @@ export const OutputContainer = ({ isQuoteStale }: OutputContainerProps) => {
const { bridgeQuote, isLoading } = useBridgeQuoteState()
const { showDestinationAddress } = useBridgeDisplayState()
const { hasValidInput, hasValidQuote } = useBridgeValidations()
+ const { debouncedFromValue, fromChainId, toChainId } = useBridgeState()
const showValue = useMemo(() => {
if (!hasValidInput) {
@@ -43,7 +45,7 @@ export const OutputContainer = ({ isQuoteStale }: OutputContainerProps) => {
- {showDestinationAddress ? (
+ {showDestinationAddress && toChainId !== HYPERLIQUID.id ? (
) : null}
@@ -52,7 +54,11 @@ export const OutputContainer = ({ isQuoteStale }: OutputContainerProps) => {
diff --git a/packages/synapse-interface/components/StateManagedBridge/hooks/useBridgeValidations.ts b/packages/synapse-interface/components/StateManagedBridge/hooks/useBridgeValidations.ts
index b3f31ab0f6..58084cf65b 100644
--- a/packages/synapse-interface/components/StateManagedBridge/hooks/useBridgeValidations.ts
+++ b/packages/synapse-interface/components/StateManagedBridge/hooks/useBridgeValidations.ts
@@ -8,6 +8,7 @@ import { BridgeQuoteState } from '@/slices/bridgeQuote/reducer'
import { EMPTY_BRIDGE_QUOTE } from '@/constants/bridge'
import { hasOnlyZeroes } from '@/utils/hasOnlyZeroes'
import { useBridgeSelections } from './useBridgeSelections'
+import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master'
export const useBridgeValidations = () => {
const { chainId } = useAccount()
@@ -66,7 +67,7 @@ export const useBridgeValidations = () => {
debouncedFromValue,
fromChainId,
fromToken,
- toChainId,
+ toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId,
toToken
)
}, [debouncedFromValue, fromChainId, fromToken, toChainId, toToken])
diff --git a/packages/synapse-interface/components/_Transaction/_Transaction.tsx b/packages/synapse-interface/components/_Transaction/_Transaction.tsx
index 1aea90352b..4ffb331305 100644
--- a/packages/synapse-interface/components/_Transaction/_Transaction.tsx
+++ b/packages/synapse-interface/components/_Transaction/_Transaction.tsx
@@ -20,6 +20,7 @@ import { RightArrow } from '@/components/icons/RightArrow'
import { Address } from 'viem'
import { useIsTxReverted } from './helpers/useIsTxReverted'
import { useTxRefundStatus } from './helpers/useTxRefundStatus'
+import { HYPERLIQUID } from '@/constants/chains/master'
interface _TransactionProps {
connectedAddress: string
@@ -185,13 +186,15 @@ export const _Transaction = ({
iconUrl={originChain?.explorerImg}
/>
)}
- {!isNull(destExplorerAddressLink) && !isTxReverted && (
-
- )}
+ {destinationChain.id !== HYPERLIQUID.id &&
+ !isNull(destExplorerAddressLink) &&
+ !isTxReverted && (
+
+ )}
)
diff --git a/packages/synapse-interface/components/layouts/LandingPageWrapper/index.tsx b/packages/synapse-interface/components/layouts/LandingPageWrapper/index.tsx
index aef82543a5..b92be9138f 100644
--- a/packages/synapse-interface/components/layouts/LandingPageWrapper/index.tsx
+++ b/packages/synapse-interface/components/layouts/LandingPageWrapper/index.tsx
@@ -59,10 +59,10 @@ export function LandingPageWrapper({ children }: { children: any }) {
style={TODO_REMOVE_wrapperStyle}
>
diff --git a/packages/synapse-interface/constants/chains/master.tsx b/packages/synapse-interface/constants/chains/master.tsx
index ad44fa27a6..5c687828bb 100644
--- a/packages/synapse-interface/constants/chains/master.tsx
+++ b/packages/synapse-interface/constants/chains/master.tsx
@@ -11,6 +11,7 @@ import dfkImg from '@assets/chains/dfk.svg'
import dogechainImg from '@assets/chains/dogechain.svg'
import ethImg from '@assets/chains/ethereum.svg'
import fantomImg from '@assets/chains/fantom.svg'
+import hyperliquidImg from '@assets/chains/hyperliquid.svg'
import harmonyImg from '@assets/chains/harmony.svg'
import klaytnImg from '@assets/chains/klaytn.svg'
import metisImg from '@assets/chains/metis.svg'
@@ -615,5 +616,31 @@ export const WORLDCHAIN: Chain = {
icon: ethImg,
},
color: 'black',
+}
+
+export const HYPERLIQUID: Chain = {
+ priorityRank: 99,
+ id: 998, // this is Hyperliquid Testnet from their docs
+ chainSymbol: 'HYPERLIQUID',
+ name: 'Hyperliquid',
+ chainImg: hyperliquidImg,
+ layer: 2,
+ blockTime: 300,
+ rpcUrls: {
+ primary:
+ 'https://arb-mainnet.g.alchemy.com/v2/7kjdkqKTh1zQ1mRYGi4nJJbxbyJXHkef',
+ fallback: 'https://arb1.arbitrum.io/rpc',
+ },
+ nativeCurrency: {
+ name: 'Ethereum',
+ symbol: 'ETH',
+ decimals: 18,
+ address: zeroAddress,
+ icon: ethImg,
+ },
+ explorerUrl: 'https://arbiscan.io',
+ explorerName: 'Arbiscan',
+ explorerImg: arbitrumExplorerImg,
+ color: 'gray',
isNew: true,
}
diff --git a/packages/synapse-interface/constants/existingBridgeRoutes.ts b/packages/synapse-interface/constants/existingBridgeRoutes.ts
index a1ec85b06f..3f1213399a 100644
--- a/packages/synapse-interface/constants/existingBridgeRoutes.ts
+++ b/packages/synapse-interface/constants/existingBridgeRoutes.ts
@@ -1,5 +1,8 @@
+import _ from 'lodash'
+
import { BRIDGE_MAP } from '@/constants/bridgeMap'
import { flattenPausedTokens } from '@/utils/flattenPausedTokens'
+import { HYPERLIQUID } from './chains/master'
export type BridgeRoutes = Record
@@ -46,9 +49,19 @@ const constructJSON = (swappableMap, exclusionList) => {
return result
}
+const addUSDCHyperLiquid = (routes) => {
+ const usdcHyperliquid = `USDC-${HYPERLIQUID.id}`
+
+ return _.mapValues(routes, (innerList, key) => {
+ // If the key is USDC-42161 OR if the innerList includes USDC-42161
+ if (key === 'USDC-42161' || innerList.includes('USDC-42161')) {
+ return [...innerList, usdcHyperliquid]
+ }
+ return innerList
+ })
+}
const PAUSED_TOKENS = flattenPausedTokens()
-export const EXISTING_BRIDGE_ROUTES: BridgeRoutes = constructJSON(
- BRIDGE_MAP,
- PAUSED_TOKENS
+export const EXISTING_BRIDGE_ROUTES: BridgeRoutes = addUSDCHyperLiquid(
+ constructJSON(BRIDGE_MAP, PAUSED_TOKENS)
)
diff --git a/packages/synapse-interface/constants/index.ts b/packages/synapse-interface/constants/index.ts
index 85e1dee41c..bcbf8a4ed2 100644
--- a/packages/synapse-interface/constants/index.ts
+++ b/packages/synapse-interface/constants/index.ts
@@ -2,3 +2,5 @@ export const MAX_UINT256 =
115792089237316195423570985008687907853269984665640564039457584007913129639935n
export const ETHEREUM_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
+
+export const HYPERLIQUID_MINIMUM_DEPOSIT = 5
diff --git a/packages/synapse-interface/messages/ar.json b/packages/synapse-interface/messages/ar.json
index 09f07631d4..91739c4166 100644
--- a/packages/synapse-interface/messages/ar.json
+++ b/packages/synapse-interface/messages/ar.json
@@ -18,6 +18,8 @@
"Please select Destination network": "يرجى اختيار شبكة الوجهة",
"Please select an Origin token": "يرجى اختيار رمز المصدر",
"Bridge {symbol}": "جسر {symbol}",
+ "Deposit {symbol}": "إيداع {symbol}",
+ "Depositing": "الإيداع",
"Connect Wallet to Bridge": "اتصل بالمحفظة للجسر",
"Amount must be greater than fee": "يجب أن يكون المبلغ أكبر من الرسوم",
"Error in bridge quote": "خطأ في عرض الجسر",
diff --git a/packages/synapse-interface/messages/en-US.json b/packages/synapse-interface/messages/en-US.json
index 8452406b49..c510d85681 100644
--- a/packages/synapse-interface/messages/en-US.json
+++ b/packages/synapse-interface/messages/en-US.json
@@ -18,6 +18,8 @@
"Please select Destination network": "Please select Destination network",
"Please select an Origin token": "Please select an Origin token",
"Bridge {symbol}": "Bridge {symbol}",
+ "Deposit {symbol}": "Deposit {symbol}",
+ "Depositing": "Depositing",
"Connect Wallet to Bridge": "Connect Wallet to Bridge",
"Amount must be greater than fee": "Amount must be greater than fee",
"Error in bridge quote": "Error in bridge quote",
diff --git a/packages/synapse-interface/messages/es.json b/packages/synapse-interface/messages/es.json
index 5c121dfbe6..d36bd2ed97 100644
--- a/packages/synapse-interface/messages/es.json
+++ b/packages/synapse-interface/messages/es.json
@@ -18,6 +18,8 @@
"Please select Destination network": "Por favor, selecciona la red de Destino",
"Please select an Origin token": "Por favor, selecciona un token de Origen",
"Bridge {symbol}": "Puente {symbol}",
+ "Deposit {symbol}": "Depósito {symbol}",
+ "Depositing": "Depositando",
"Connect Wallet to Bridge": "Conecta la Wallet para usar el Puente",
"Amount must be greater than fee": "La cantidad debe ser mayor que la comisión",
"Error in bridge quote": "Error en la cotización del puente",
diff --git a/packages/synapse-interface/messages/fr.json b/packages/synapse-interface/messages/fr.json
index 5f4608d38e..1294c50566 100644
--- a/packages/synapse-interface/messages/fr.json
+++ b/packages/synapse-interface/messages/fr.json
@@ -18,6 +18,8 @@
"Please select Destination network": "Veuillez sélectionner le réseau de destination",
"Please select an Origin token": "Veuillez sélectionner un jeton d'origine",
"Bridge {symbol}": "Bridge {symbol}",
+ "Deposit {symbol}": "Dépôt {symbol}",
+ "Depositing": "Dépôt",
"Connect Wallet to Bridge": "Connecter le portefeuille au bridge",
"Amount must be greater than fee": "Le montant doit être supérieur aux frais",
"Error in bridge quote": "Erreur dans la citation du bridge",
diff --git a/packages/synapse-interface/messages/jp.json b/packages/synapse-interface/messages/jp.json
index ee05d2a385..bfc4354507 100644
--- a/packages/synapse-interface/messages/jp.json
+++ b/packages/synapse-interface/messages/jp.json
@@ -18,6 +18,8 @@
"Please select Destination network": "宛先ネットワークを選択してください",
"Please select an Origin token": "オリジントークンを選択してください",
"Bridge {symbol}": "{symbol}をブリッジ",
+ "Deposit {symbol}": "デポジット {symbol}",
+ "Depositing": "入金",
"Connect Wallet to Bridge": "ウォレットを接続してブリッジ",
"Amount must be greater than fee": "金額は手数料より大きくなければなりません",
"Error in bridge quote": "ブリッジ見積もりでエラーが発生しました",
diff --git a/packages/synapse-interface/messages/tr.json b/packages/synapse-interface/messages/tr.json
index d51a91667a..a281269809 100644
--- a/packages/synapse-interface/messages/tr.json
+++ b/packages/synapse-interface/messages/tr.json
@@ -18,6 +18,8 @@
"Please select Destination network": "Lütfen Hedef ağı seçin",
"Please select an Origin token": "Lütfen bir Kaynak token seçin",
"Bridge {symbol}": "{symbol} Köprüsü",
+ "Deposit {symbol}": "Depozito {symbol}",
+ "Depositing": "Para yatırma",
"Connect Wallet to Bridge": "Köprü için Cüzdanı Bağla",
"Amount must be greater than fee": "Miktar ücretten büyük olmalıdır",
"Error in bridge quote": "Köprü teklifinde hata",
diff --git a/packages/synapse-interface/messages/zh-CN.json b/packages/synapse-interface/messages/zh-CN.json
index d6a864354b..72f05a5048 100644
--- a/packages/synapse-interface/messages/zh-CN.json
+++ b/packages/synapse-interface/messages/zh-CN.json
@@ -18,6 +18,8 @@
"Please select Destination network": "请选择目标网络",
"Please select an Origin token": "请选择来源代币",
"Bridge {symbol}": "桥接 {symbol}",
+ "Deposit {symbol}": "存入 {symbol}",
+ "Depositing": "存款",
"Connect Wallet to Bridge": "连接钱包以桥接",
"Amount must be greater than fee": "金额必须大于费用",
"Error in bridge quote": "桥接报价错误",
diff --git a/packages/synapse-interface/pages/state-managed-bridge/index.tsx b/packages/synapse-interface/pages/state-managed-bridge/index.tsx
index f328d668e7..f4c3f63298 100644
--- a/packages/synapse-interface/pages/state-managed-bridge/index.tsx
+++ b/packages/synapse-interface/pages/state-managed-bridge/index.tsx
@@ -9,6 +9,7 @@ import {
getWalletClient,
getPublicClient,
waitForTransactionReceipt,
+ switchChain,
} from '@wagmi/core'
import { useTranslations } from 'next-intl'
@@ -47,7 +48,10 @@ import { Token } from '@/utils/types'
import { txErrorHandler } from '@/utils/txErrorHandler'
import { approveToken } from '@/utils/approveToken'
import { stringToBigInt } from '@/utils/bigint/format'
-import { fetchAndStoreSingleNetworkPortfolioBalances } from '@/slices/portfolio/hooks'
+import {
+ fetchAndStoreSingleNetworkPortfolioBalances,
+ usePortfolioState,
+} from '@/slices/portfolio/hooks'
import {
updatePendingBridgeTransaction,
addPendingBridgeTransaction,
@@ -69,10 +73,17 @@ import { isTransactionUserRejectedError } from '@/utils/isTransactionUserRejecte
import { BridgeQuoteResetTimer } from '@/components/StateManagedBridge/BridgeQuoteResetTimer'
import { useBridgeValidations } from '@/components/StateManagedBridge/hooks/useBridgeValidations'
import { useStaleQuoteUpdater } from '@/components/StateManagedBridge/hooks/useStaleQuoteUpdater'
+import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master'
+import { HyperliquidTransactionButton } from '@/components/StateManagedBridge/HyperliquidDepositButton'
+import { USDC } from '@/constants/tokens/bridgeable'
+import { CheckCircleIcon } from '@heroicons/react/outline'
+import Image from 'next/image'
+import { HyperliquidDepositInfo } from '@/components/HyperliquidDepositInfo'
const StateManagedBridge = () => {
const dispatch = useAppDispatch()
- const { address, isConnected } = useAccount()
+ const { address, isConnected, chain: connectedChain } = useAccount()
+ const { balances } = usePortfolioState()
const { synapseSDK } = useSynapseContext()
const router = useRouter()
const { query, pathname } = router
@@ -86,6 +97,9 @@ const StateManagedBridge = () => {
const [isTyping, setIsTyping] = useState(false)
+ const [hasDepositedOnHyperliquid, setHasDepositedOnHyperliquid] =
+ useState(false)
+
const {
fromChainId,
toChainId,
@@ -154,7 +168,7 @@ const StateManagedBridge = () => {
fetchBridgeQuote({
synapseSDK,
fromChainId,
- toChainId,
+ toChainId: toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId,
fromToken,
toToken,
debouncedFromValue,
@@ -182,7 +196,10 @@ const StateManagedBridge = () => {
quoteToastRef.current.id = toast(message, { duration: 3000 })
}
- if (fetchBridgeQuote.rejected.match(result)) {
+ if (
+ fetchBridgeQuote.rejected.match(result) &&
+ !(fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id)
+ ) {
const message = t(
'No route found for bridging {debouncedFromValue} {fromToken} on {fromChainId} to {toToken} on {toChainId}',
{
@@ -275,7 +292,8 @@ const StateManagedBridge = () => {
{
id: bridgeQuote.id,
originChainId: fromChainId,
- destinationChainId: toChainId,
+ destinationChainId:
+ toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId,
inputAmount: debouncedFromValue,
expectedReceivedAmount: bridgeQuote.outputAmountString,
slippage: bridgeQuote.exchangeRate,
@@ -294,7 +312,8 @@ const StateManagedBridge = () => {
originChain: CHAINS_BY_ID[fromChainId],
originToken: fromToken,
originValue: debouncedFromValue,
- destinationChain: CHAINS_BY_ID[toChainId],
+ destinationChain:
+ CHAINS_BY_ID[toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId],
destinationToken: toToken,
transactionHash: undefined,
timestamp: undefined,
@@ -319,7 +338,7 @@ const StateManagedBridge = () => {
toAddress,
bridgeQuote.routerAddress,
fromChainId,
- toChainId,
+ toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId,
fromToken?.addresses[fromChainId as keyof Token['addresses']],
stringToBigInt(debouncedFromValue, fromToken?.decimals[fromChainId]),
bridgeQuote.originQuery,
@@ -356,7 +375,8 @@ const StateManagedBridge = () => {
segmentAnalyticsEvent(`[Bridge] bridges successfully`, {
id: bridgeQuote.id,
originChainId: fromChainId,
- destinationChainId: toChainId,
+ destinationChainId:
+ toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId,
inputAmount: debouncedFromValue,
expectedReceivedAmount: bridgeQuote.outputAmountString,
slippage: bridgeQuote.exchangeRate,
@@ -411,6 +431,13 @@ const StateManagedBridge = () => {
timeout: 60_000,
})
+ if (toChainId === HYPERLIQUID.id) {
+ dispatch(setFromChainId(ARBITRUM.id))
+ dispatch(setFromToken(USDC))
+ dispatch(setToChainId(HYPERLIQUID.id))
+ switchChain(wagmiConfig, { chainId: ARBITRUM.id })
+ }
+
/** Update Origin Chain token balances after resolved tx or timeout reached */
/** Assume tx has been actually resolved if above times out */
dispatch(
@@ -489,17 +516,34 @@ const StateManagedBridge = () => {
-
+ {!(
+ fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id
+ ) && }
+ {toChainId === HYPERLIQUID.id && (
+
+ )}
-
+ {fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id ? (
+
+ ) : (
+
+ )}