From c445292842a9d2b9e5533e00b31cf1f6b85c8432 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Thu, 12 Dec 2024 20:45:27 -0500 Subject: [PATCH 01/12] Hyperliquid bridge wip --- .../assets/chains/hyperliquid.svg | 3 + .../HyperliquidDepositButton.tsx | 254 ++++++++++++++++++ .../StateManagedBridge/OutputContainer.tsx | 10 +- .../hooks/useBridgeValidations.ts | 3 +- .../components/ui/CopyButton.tsx | 26 ++ .../constants/chains/master.tsx | 27 ++ .../constants/existingBridgeRoutes.ts | 19 +- packages/synapse-interface/messages/ar.json | 2 + .../synapse-interface/messages/en-US.json | 2 + packages/synapse-interface/messages/es.json | 2 + packages/synapse-interface/messages/fr.json | 2 + packages/synapse-interface/messages/jp.json | 2 + packages/synapse-interface/messages/tr.json | 2 + .../synapse-interface/messages/zh-CN.json | 2 + .../pages/state-managed-bridge/index.tsx | 53 ++-- .../slices/bridge/reducer.ts | 4 + .../slices/bridgeQuote/thunks.ts | 11 +- .../utils/hooks/useHyperliquidTransaction.ts | 5 + 18 files changed, 407 insertions(+), 22 deletions(-) create mode 100644 packages/synapse-interface/assets/chains/hyperliquid.svg create mode 100644 packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx create mode 100644 packages/synapse-interface/components/ui/CopyButton.tsx create mode 100644 packages/synapse-interface/utils/hooks/useHyperliquidTransaction.ts 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/StateManagedBridge/HyperliquidDepositButton.tsx b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx new file mode 100644 index 0000000000..af260ac0eb --- /dev/null +++ b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx @@ -0,0 +1,254 @@ +import { useEffect, useState } from 'react' +import { useAccount, useAccountEffect, useSwitchChain } from 'wagmi' +import { useConnectModal } from '@rainbow-me/rainbowkit' +import { useTranslations } from 'next-intl' + +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 { Address, erc20Abi } from 'viem' +import { MAX_UINT256 } from '@/constants' +import { wagmiConfig } from '@/wagmiConfig' +import { + simulateContract, + waitForTransactionReceipt, + writeContract, +} from '@wagmi/core' +import { stringToBigInt } from '@/utils/bigint/format' +import { set } from 'lodash' +import { arbitrum } from 'viem/chains' +import { ArrowRightIcon, CheckCircleIcon } from '@heroicons/react/outline' +import { ArrowUpRightIcon } from '../icons/ArrowUpRightIcon' +import { shortenAddress } from '@/utils/shortenAddress' +import Image from 'next/image' +import { CopyButton } from '../ui/CopyButton' +import { fetchAndStoreSingleNetworkPortfolioBalances } from '@/slices/portfolio/hooks' + +const HYPERLIQUID_DEPOSIT_ADDRESS = '0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7' + +const approve = async (address: Address, amount: bigint) => { + const { request } = await simulateContract(wagmiConfig, { + chainId: ARBITRUM.id, + address: USDC.addresses[ARBITRUM.id], + abi: erc20Abi, + functionName: 'approve', + args: [address, amount], + }) + + const hash = await writeContract(wagmiConfig, request) + + const txReceipt = await waitForTransactionReceipt(wagmiConfig, { hash }) + + return txReceipt +} + +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 }) => { + const [isApproved, setIsApproved] = useState(false) + const [isApproving, setIsApproving] = useState(false) + const [isDepositing, setIsDepositing] = useState(false) + const [hasDeposited, setHasDeposited] = useState(false) + const [depositHash, setDepositHash] = useState('') + + 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) >= 5 + + const t = useTranslations('Bridge') + + const amount = stringToBigInt( + debouncedFromValue, + fromToken.decimals[fromChainId] + ) + + const handleApprove = async () => { + setIsApproving(true) + + try { + await approve(address, amount) + setIsApproved(true) + } catch (error) { + console.error('Approval error:', error) + } finally { + setIsApproving(false) + } + } + + const handleDeposit = async () => { + setIsDepositing(true) + try { + const txReceipt = await deposit(amount) + + setDepositHash(txReceipt.transactionHash) + setHasDeposited(true) + setIsApproved(false) + dispatch( + fetchAndStoreSingleNetworkPortfolioBalances({ + address, + chainId: ARBITRUM.id, + }) + ) + } catch (error) { + console.error('Deposit error:', error) + } finally { + setIsDepositing(false) + } + } + + useEffect(() => { + // refresh balances + }, []) + + useAccountEffect({ + onDisconnect() { + setIsConnected(false) + }, + }) + + useEffect(() => { + setIsConnected(isConnectedInit) + }, [isConnectedInit]) + + const isButtonDisabled = + isTyping || + isApproving || + isDepositing || + !depositingMinimumAmount || + isWalletPending || + !hasValidInput || + (isConnected && !hasSufficientBalance) + + let buttonProperties + + if (isConnected && !hasSufficientBalance) { + buttonProperties = { + label: t('Insufficient balance'), + onClick: null, + } + } else if (!depositingMinimumAmount) { + buttonProperties = { + label: '5 USDC Minimum', + onClick: null, + } + } else if (!isConnected && hasValidInput) { + buttonProperties = { + label: t('Connect Wallet to Deposit'), + 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 if (!isApproved && hasValidInput) { + buttonProperties = { + onClick: handleApprove, + label: t('Approve {symbol}', { symbol: fromToken?.symbol }), + pendingLabel: t('Approving'), + } + } else { + buttonProperties = { + onClick: handleDeposit, + label: t('Deposit {symbol}', { symbol: fromToken?.symbol }), + pendingLabel: t('Depositing'), + } + } + + return ( + buttonProperties && ( + <> +
+ {hasDeposited && ( +
+
+ Switch Network + +
Hyperliquid Deposit
+
+
+
+ Receipt: {' '} + {shortenAddress(depositHash, 8)}{' '} + / + +
+ +
+ Arbiscan +
{arbitrum.blockExplorers.default.name}
+ +
+
+
+
+ )} + + +
+ + ) + ) +} 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/ui/CopyButton.tsx b/packages/synapse-interface/components/ui/CopyButton.tsx new file mode 100644 index 0000000000..efa51c58e2 --- /dev/null +++ b/packages/synapse-interface/components/ui/CopyButton.tsx @@ -0,0 +1,26 @@ +import React, { useState } from 'react' + +const copyToClipboard = (text: string) => { + navigator.clipboard.writeText(text) +} + +export const CopyButton = ({ text }: { text: string }) => { + const [isClicked, setIsClicked] = useState(false) + + const handleCopyClick = () => { + copyToClipboard(text) + setIsClicked(true) + } + + return ( + + ) +} 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/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..eed90c1406 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..ba37fef12c 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' @@ -69,6 +70,9 @@ 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' const StateManagedBridge = () => { const dispatch = useAppDispatch() @@ -154,7 +158,7 @@ const StateManagedBridge = () => { fetchBridgeQuote({ synapseSDK, fromChainId, - toChainId, + toChainId: toChainId === HYPERLIQUID.id ? 42161 : toChainId, fromToken, toToken, debouncedFromValue, @@ -182,7 +186,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 +282,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 +302,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 +328,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 +365,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 +421,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 +506,23 @@ const StateManagedBridge = () => { - + {!( + fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id + ) && }
- + {fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id ? ( + + ) : ( + + )}
+ chainId === HYPERLIQUID.id ? ARBITRUM.id : chainId + export const initialState: BridgeState = { fromChainId, fromToken, diff --git a/packages/synapse-interface/slices/bridgeQuote/thunks.ts b/packages/synapse-interface/slices/bridgeQuote/thunks.ts index 6a3970cb8b..f4c4b61902 100644 --- a/packages/synapse-interface/slices/bridgeQuote/thunks.ts +++ b/packages/synapse-interface/slices/bridgeQuote/thunks.ts @@ -10,6 +10,7 @@ import { calculateExchangeRate } from '@/utils/calculateExchangeRate' import { getBridgeModuleNames } from '@/utils/getBridgeModuleNames' import { Token } from '@/utils/types' import { BridgeModulePause } from '@/components/Maintenance/Maintenance' +import { HYPERLIQUID } from '@/constants/chains/master' export const fetchBridgeQuote = createAsyncThunk( 'bridgeQuote/fetchBridgeQuote', @@ -119,7 +120,15 @@ export const fetchBridgeQuote = createAsyncThunk( destChainId, } = quote - if (!(originQuery && maxAmountOut && destQuery && feeAmount)) { + if ( + !( + originQuery && + maxAmountOut && + destQuery && + feeAmount && + toChainId !== HYPERLIQUID.id + ) + ) { const msg = `No route found for bridging ${debouncedFromValue} ${fromToken?.symbol} on ${CHAINS_BY_ID[fromChainId]?.name} to ${toToken?.symbol} on ${CHAINS_BY_ID[toChainId]?.name}` return rejectWithValue(msg) } diff --git a/packages/synapse-interface/utils/hooks/useHyperliquidTransaction.ts b/packages/synapse-interface/utils/hooks/useHyperliquidTransaction.ts new file mode 100644 index 0000000000..94bc281d1b --- /dev/null +++ b/packages/synapse-interface/utils/hooks/useHyperliquidTransaction.ts @@ -0,0 +1,5 @@ +import { useBridgeState } from '@/slices/bridge/hooks' + +export const useHyperliquidTransaction = () => { + const { toChainId } = useBridgeState() +} From d10ee5c15b09da01ff21fbd27b33990eb7b6ad39 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 13:42:06 -0500 Subject: [PATCH 02/12] Moves receipt into Activity transactions --- .../components/HyperliquidDepositInfo.tsx | 45 ++++++++ .../HyperliquidDepositButton.tsx | 106 +++++++----------- .../components/_Transaction/_Transaction.tsx | 17 +-- .../components/_Transaction/_Transactions.tsx | 7 +- .../components/ui/CopyButton.tsx | 26 ----- .../pages/state-managed-bridge/index.tsx | 27 ++++- .../utils/hooks/useHyperliquidTransaction.ts | 5 - 7 files changed, 123 insertions(+), 110 deletions(-) create mode 100644 packages/synapse-interface/components/HyperliquidDepositInfo.tsx delete mode 100644 packages/synapse-interface/components/ui/CopyButton.tsx delete mode 100644 packages/synapse-interface/utils/hooks/useHyperliquidTransaction.ts diff --git a/packages/synapse-interface/components/HyperliquidDepositInfo.tsx b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx new file mode 100644 index 0000000000..9178453dab --- /dev/null +++ b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx @@ -0,0 +1,45 @@ +import Image from 'next/image' +import { CheckCircleIcon } from '@heroicons/react/outline' + +import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master' + +export const HyperliquidDepositInfo = ({ + fromChainId, + isOnArbitrum, + hasDepositedOnHyperliquid, +}) => { + return ( +
+
+ Switch Network + +
Hyperliquid Deposit
+
+
+ +
Bridge to Arbitrum
+
+
+ +
Deposit to Hyperliquid
+
+
+ ) +} diff --git a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx index af260ac0eb..bef2729a16 100644 --- a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx @@ -2,7 +2,14 @@ import { useEffect, useState } from 'react' import { useAccount, useAccountEffect, useSwitchChain } from 'wagmi' import { useConnectModal } from '@rainbow-me/rainbowkit' import { useTranslations } from 'next-intl' +import { Address, 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' @@ -10,23 +17,11 @@ 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 { Address, erc20Abi } from 'viem' -import { MAX_UINT256 } from '@/constants' -import { wagmiConfig } from '@/wagmiConfig' -import { - simulateContract, - waitForTransactionReceipt, - writeContract, -} from '@wagmi/core' import { stringToBigInt } from '@/utils/bigint/format' -import { set } from 'lodash' -import { arbitrum } from 'viem/chains' -import { ArrowRightIcon, CheckCircleIcon } from '@heroicons/react/outline' -import { ArrowUpRightIcon } from '../icons/ArrowUpRightIcon' -import { shortenAddress } from '@/utils/shortenAddress' -import Image from 'next/image' -import { CopyButton } from '../ui/CopyButton' import { fetchAndStoreSingleNetworkPortfolioBalances } from '@/slices/portfolio/hooks' +import { segmentAnalyticsEvent } from '@/contexts/SegmentAnalyticsProvider' +import { addPendingBridgeTransaction } from '@/slices/transactions/actions' +import { getUnixTimeMinutesFromNow } from '@/utils/time' const HYPERLIQUID_DEPOSIT_ADDRESS = '0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7' @@ -67,12 +62,14 @@ const deposit = async (amount: bigint) => { } } -export const HyperliquidTransactionButton = ({ isTyping }) => { +export const HyperliquidTransactionButton = ({ + isTyping, + hasDepositedOnHyperliquid, + setHasDepositedOnHyperliquid, +}) => { const [isApproved, setIsApproved] = useState(false) const [isApproving, setIsApproving] = useState(false) const [isDepositing, setIsDepositing] = useState(false) - const [hasDeposited, setHasDeposited] = useState(false) - const [depositHash, setDepositHash] = useState('') const { address } = useAccount() @@ -114,18 +111,38 @@ export const HyperliquidTransactionButton = ({ isTyping }) => { const handleDeposit = async () => { setIsDepositing(true) + const currentTimestamp: number = getUnixTimeMinutesFromNow(0) try { const txReceipt = await deposit(amount) - setDepositHash(txReceipt.transactionHash) - setHasDeposited(true) + setHasDepositedOnHyperliquid(true) setIsApproved(false) + 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 { @@ -133,10 +150,6 @@ export const HyperliquidTransactionButton = ({ isTyping }) => { } } - useEffect(() => { - // refresh balances - }, []) - useAccountEffect({ onDisconnect() { setIsConnected(false) @@ -170,7 +183,7 @@ export const HyperliquidTransactionButton = ({ isTyping }) => { } } else if (!isConnected && hasValidInput) { buttonProperties = { - label: t('Connect Wallet to Deposit'), + label: t('Connect Wallet to Bridge'), onClick: openConnectModal, } } else if (!onSelectedChain && hasValidInput) { @@ -199,49 +212,6 @@ export const HyperliquidTransactionButton = ({ isTyping }) => { buttonProperties && ( <>
- {hasDeposited && ( -
-
- Switch Network - -
Hyperliquid Deposit
-
-
-
- Receipt: {' '} - {shortenAddress(depositHash, 8)}{' '} - / - -
- -
- Arbiscan -
{arbitrum.blockExplorers.default.name}
- -
-
-
-
- )} - )} - {!isNull(destExplorerAddressLink) && !isTxReverted && ( - - )} + {destinationChain.id !== HYPERLIQUID.id && + !isNull(destExplorerAddressLink) && + !isTxReverted && ( + + )} ) diff --git a/packages/synapse-interface/components/ui/CopyButton.tsx b/packages/synapse-interface/components/ui/CopyButton.tsx deleted file mode 100644 index efa51c58e2..0000000000 --- a/packages/synapse-interface/components/ui/CopyButton.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useState } from 'react' - -const copyToClipboard = (text: string) => { - navigator.clipboard.writeText(text) -} - -export const CopyButton = ({ text }: { text: string }) => { - const [isClicked, setIsClicked] = useState(false) - - const handleCopyClick = () => { - copyToClipboard(text) - setIsClicked(true) - } - - return ( - - ) -} diff --git a/packages/synapse-interface/pages/state-managed-bridge/index.tsx b/packages/synapse-interface/pages/state-managed-bridge/index.tsx index ba37fef12c..dc9952a1ab 100644 --- a/packages/synapse-interface/pages/state-managed-bridge/index.tsx +++ b/packages/synapse-interface/pages/state-managed-bridge/index.tsx @@ -48,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, @@ -73,10 +76,14 @@ import { useStaleQuoteUpdater } from '@/components/StateManagedBridge/hooks/useS 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 @@ -90,6 +97,9 @@ const StateManagedBridge = () => { const [isTyping, setIsTyping] = useState(false) + const [hasDepositedOnHyperliquid, setHasDepositedOnHyperliquid] = + useState(false) + const { fromChainId, toChainId, @@ -509,10 +519,21 @@ const StateManagedBridge = () => { {!( fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id ) && } + {toChainId === HYPERLIQUID.id && ( + + )}
{fromChainId === ARBITRUM.id && toChainId === HYPERLIQUID.id ? ( - + ) : ( { - const { toChainId } = useBridgeState() -} From 5254bbca948f0f8fd024b464c304b1ba362d6654 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 13:45:37 -0500 Subject: [PATCH 03/12] Lint --- packages/synapse-interface/slices/bridge/reducer.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/synapse-interface/slices/bridge/reducer.ts b/packages/synapse-interface/slices/bridge/reducer.ts index 3390a9caf7..fa48546045 100644 --- a/packages/synapse-interface/slices/bridge/reducer.ts +++ b/packages/synapse-interface/slices/bridge/reducer.ts @@ -12,7 +12,6 @@ import { getToChainIds } from '@/utils/routeMaker/getToChainIds' import { getToTokens } from '@/utils/routeMaker/getToTokens' import { findTokenByRouteSymbol } from '@/utils/findTokenByRouteSymbol' import { findValidToken } from '@/utils/findValidToken' -import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master' export interface BridgeState { fromChainId: number @@ -46,9 +45,6 @@ const { toToken: null, }) -const transformToChainId = (chainId: number | null) => - chainId === HYPERLIQUID.id ? ARBITRUM.id : chainId - export const initialState: BridgeState = { fromChainId, fromToken, From e1d62dce4d2fee3e2b05ef218b76841389d02f3b Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 13:52:32 -0500 Subject: [PATCH 04/12] Spellchecker --- cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.json b/cspell.json index 059350f412..e4b57b352a 100644 --- a/cspell.json +++ b/cspell.json @@ -42,6 +42,7 @@ "gitbook", "gorm", "headlessui", + "hyperliquid", "incentivized", "interchain", "ipfs", From e3535b112feaeeaa7224d267f34707892de07926 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 13:58:56 -0500 Subject: [PATCH 05/12] Rec changes --- packages/synapse-interface/messages/zh-CN.json | 2 +- packages/synapse-interface/pages/state-managed-bridge/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/synapse-interface/messages/zh-CN.json b/packages/synapse-interface/messages/zh-CN.json index eed90c1406..72f05a5048 100644 --- a/packages/synapse-interface/messages/zh-CN.json +++ b/packages/synapse-interface/messages/zh-CN.json @@ -18,7 +18,7 @@ "Please select Destination network": "请选择目标网络", "Please select an Origin token": "请选择来源代币", "Bridge {symbol}": "桥接 {symbol}", - "Deposit {symbol}": "订金 {symbol}", + "Deposit {symbol}": "存入 {symbol}", "Depositing": "存款", "Connect Wallet to Bridge": "连接钱包以桥接", "Amount must be greater than fee": "金额必须大于费用", diff --git a/packages/synapse-interface/pages/state-managed-bridge/index.tsx b/packages/synapse-interface/pages/state-managed-bridge/index.tsx index dc9952a1ab..f4c3f63298 100644 --- a/packages/synapse-interface/pages/state-managed-bridge/index.tsx +++ b/packages/synapse-interface/pages/state-managed-bridge/index.tsx @@ -168,7 +168,7 @@ const StateManagedBridge = () => { fetchBridgeQuote({ synapseSDK, fromChainId, - toChainId: toChainId === HYPERLIQUID.id ? 42161 : toChainId, + toChainId: toChainId === HYPERLIQUID.id ? ARBITRUM.id : toChainId, fromToken, toToken, debouncedFromValue, From f948d4d0e12b653a84e5f244ffbae1d454d2d8bd Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 14:01:05 -0500 Subject: [PATCH 06/12] Announcement banner --- .../components/layouts/LandingPageWrapper/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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} > From 9e9afb0ef4e01b8c70fed27e99aef3266e76ad87 Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 14:38:21 -0500 Subject: [PATCH 07/12] Checks undefined fromToken --- .../components/StateManagedBridge/HyperliquidDepositButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx index bef2729a16..94c14aabef 100644 --- a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx @@ -93,7 +93,7 @@ export const HyperliquidTransactionButton = ({ const amount = stringToBigInt( debouncedFromValue, - fromToken.decimals[fromChainId] + fromToken?.decimals[fromChainId] ) const handleApprove = async () => { From af05fe7009e05d6b1a2fa0a746a3d4b021891d1a Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 16:16:27 -0500 Subject: [PATCH 08/12] Step indicator --- .../components/HyperliquidDepositInfo.tsx | 204 +++++++++++++++--- 1 file changed, 170 insertions(+), 34 deletions(-) diff --git a/packages/synapse-interface/components/HyperliquidDepositInfo.tsx b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx index 9178453dab..469159c769 100644 --- a/packages/synapse-interface/components/HyperliquidDepositInfo.tsx +++ b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx @@ -1,45 +1,181 @@ -import Image from 'next/image' -import { CheckCircleIcon } from '@heroicons/react/outline' - -import { ARBITRUM, HYPERLIQUID } from '@/constants/chains/master' +import { ARBITRUM } from '@/constants/chains/master' export const HyperliquidDepositInfo = ({ fromChainId, isOnArbitrum, hasDepositedOnHyperliquid, }) => { - return ( -
-
- Switch Network - -
Hyperliquid Deposit
+ if (fromChainId !== ARBITRUM.id) { + return ( +
+
+
+
Step 1
+
+ +
Bridge (Arbitrum)
+
+
+
+
Step 2
+
+ +
Deposit (Hyperliquid)
+
+
+
-
- -
Bridge to Arbitrum
+ ) + } + + if (hasDepositedOnHyperliquid) { + return ( +
+
+
+
Step 1
+
+ +
Bridge (Arbitrum)
+
+
+
+
Step 2
+
+ +
Deposit (Hyperliquid)
+
+
+
-
- -
Deposit to Hyperliquid
+ ) + } + + if (fromChainId === ARBITRUM.id && isOnArbitrum) { + return ( +
+
+
+
Step 1
+
+ +
Bridge (Arbitrum)
+
+
+
+
Step 2
+
+ +
Deposit (Hyperliquid)
+
+
+
-
+ ) + } +} + +const CompletedCheckMarkCircle = () => { + return ( + + + + + + ) +} + +const GreenStep1Circle = () => { + return ( + + + + + ) +} + +const GreenStep2Circle = () => { + return ( + + + + + ) +} + +const GrayStep2Circle = () => { + return ( + + + + ) } From 9dfe04f5688f2383c0178a9c73b9634f56d8ec9b Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 16:44:38 -0500 Subject: [PATCH 09/12] Minimum deposit --- .../BridgeTransactionButton.tsx | 17 ++++++++++++++++- .../HyperliquidDepositButton.tsx | 6 ++++-- packages/synapse-interface/constants/index.ts | 2 ++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/BridgeTransactionButton.tsx b/packages/synapse-interface/components/StateManagedBridge/BridgeTransactionButton.tsx index 86f6006650..d1621313a4 100644 --- a/packages/synapse-interface/components/StateManagedBridge/BridgeTransactionButton.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/BridgeTransactionButton.tsx @@ -13,6 +13,8 @@ import { TransactionButton } from '@/components/buttons/TransactionButton' import { useBridgeValidations } from './hooks/useBridgeValidations' import { segmentAnalyticsEvent } from '@/contexts/SegmentAnalyticsProvider' import { useConfirmNewBridgePrice } from './hooks/useConfirmNewBridgePrice' +import { HYPERLIQUID } from '@/constants/chains/master' +import { HYPERLIQUID_MINIMUM_DEPOSIT } from '@/constants' export const BridgeTransactionButton = ({ approveTxn, @@ -57,6 +59,13 @@ export const BridgeTransactionButton = ({ const { showDestinationWarning, isDestinationWarningAccepted } = useBridgeDisplayState() + const hasHyperliquidMinDeposit = + toChainId === HYPERLIQUID.id + ? Number(debouncedFromValue) > 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 index 94c14aabef..6c26b521f7 100644 --- a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx @@ -22,6 +22,7 @@ import { fetchAndStoreSingleNetworkPortfolioBalances } from '@/slices/portfolio/ 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' @@ -87,7 +88,8 @@ export const HyperliquidTransactionButton = ({ const { hasValidInput, hasSufficientBalance, onSelectedChain } = useBridgeValidations() - const depositingMinimumAmount = Number(debouncedFromValue) >= 5 + const depositingMinimumAmount = + Number(debouncedFromValue) >= HYPERLIQUID_MINIMUM_DEPOSIT const t = useTranslations('Bridge') @@ -178,7 +180,7 @@ export const HyperliquidTransactionButton = ({ } } else if (!depositingMinimumAmount) { buttonProperties = { - label: '5 USDC Minimum', + label: `${HYPERLIQUID_MINIMUM_DEPOSIT} USDC Minimum`, onClick: null, } } else if (!isConnected && hasValidInput) { 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 From b1503aa470e65aa8c65dd6c1283c8a4ae1cce43a Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 16:50:49 -0500 Subject: [PATCH 10/12] Remove approval --- .../HyperliquidDepositButton.tsx | 41 +------------------ 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx index 6c26b521f7..f089a15ca2 100644 --- a/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx +++ b/packages/synapse-interface/components/StateManagedBridge/HyperliquidDepositButton.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import { useAccount, useAccountEffect, useSwitchChain } from 'wagmi' import { useConnectModal } from '@rainbow-me/rainbowkit' import { useTranslations } from 'next-intl' -import { Address, erc20Abi } from 'viem' +import { erc20Abi } from 'viem' import { simulateContract, waitForTransactionReceipt, @@ -26,22 +26,6 @@ import { HYPERLIQUID_MINIMUM_DEPOSIT } from '@/constants' const HYPERLIQUID_DEPOSIT_ADDRESS = '0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7' -const approve = async (address: Address, amount: bigint) => { - const { request } = await simulateContract(wagmiConfig, { - chainId: ARBITRUM.id, - address: USDC.addresses[ARBITRUM.id], - abi: erc20Abi, - functionName: 'approve', - args: [address, amount], - }) - - const hash = await writeContract(wagmiConfig, request) - - const txReceipt = await waitForTransactionReceipt(wagmiConfig, { hash }) - - return txReceipt -} - const deposit = async (amount: bigint) => { try { const { request } = await simulateContract(wagmiConfig, { @@ -68,8 +52,6 @@ export const HyperliquidTransactionButton = ({ hasDepositedOnHyperliquid, setHasDepositedOnHyperliquid, }) => { - const [isApproved, setIsApproved] = useState(false) - const [isApproving, setIsApproving] = useState(false) const [isDepositing, setIsDepositing] = useState(false) const { address } = useAccount() @@ -98,19 +80,6 @@ export const HyperliquidTransactionButton = ({ fromToken?.decimals[fromChainId] ) - const handleApprove = async () => { - setIsApproving(true) - - try { - await approve(address, amount) - setIsApproved(true) - } catch (error) { - console.error('Approval error:', error) - } finally { - setIsApproving(false) - } - } - const handleDeposit = async () => { setIsDepositing(true) const currentTimestamp: number = getUnixTimeMinutesFromNow(0) @@ -118,7 +87,6 @@ export const HyperliquidTransactionButton = ({ const txReceipt = await deposit(amount) setHasDepositedOnHyperliquid(true) - setIsApproved(false) segmentAnalyticsEvent(`[Hyperliquid Deposit]`, { inputAmount: debouncedFromValue, }) @@ -164,7 +132,6 @@ export const HyperliquidTransactionButton = ({ const isButtonDisabled = isTyping || - isApproving || isDepositing || !depositingMinimumAmount || isWalletPending || @@ -196,12 +163,6 @@ export const HyperliquidTransactionButton = ({ onClick: () => switchChain({ chainId: fromChainId }), pendingLabel: t('Switching chains'), } - } else if (!isApproved && hasValidInput) { - buttonProperties = { - onClick: handleApprove, - label: t('Approve {symbol}', { symbol: fromToken?.symbol }), - pendingLabel: t('Approving'), - } } else { buttonProperties = { onClick: handleDeposit, From 91798b5d2a77b1af839b0afb58a487ba4c5c770f Mon Sep 17 00:00:00 2001 From: abtestingalpha Date: Fri, 13 Dec 2024 17:09:33 -0500 Subject: [PATCH 11/12] Fix svg console errors --- .../synapse-interface/components/HyperliquidDepositInfo.tsx | 4 ++-- .../components/StateManagedBridge/BridgeQuoteResetTimer.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/synapse-interface/components/HyperliquidDepositInfo.tsx b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx index 469159c769..6d04bd8e1d 100644 --- a/packages/synapse-interface/components/HyperliquidDepositInfo.tsx +++ b/packages/synapse-interface/components/HyperliquidDepositInfo.tsx @@ -91,13 +91,13 @@ const CompletedCheckMarkCircle = () => { height="32" rx="16" stroke="#565058" - stroke-width="2" + strokeWidth="2" /> - + ) } 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" > - + - + Date: Fri, 13 Dec 2024 17:22:28 -0500 Subject: [PATCH 12/12] Spellcheck --- cspell.json | 1 + docs/bridge/blog-posts/2024-12-12-fastbridgev2-post.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index e4b57b352a..af1ce1eda0 100644 --- a/cspell.json +++ b/cspell.json @@ -37,6 +37,7 @@ "ethersproject", "ethtx", "extralight", + "fastbridge", "ftmscan", "getids", "gitbook", 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. :::